From 494085b19a9af65bb0ff87f25e4e825b771aebfa Mon Sep 17 00:00:00 2001 From: primata Date: Mon, 18 May 2026 00:35:27 -0300 Subject: [PATCH 1/9] pre fixing errors --- .../aptos-framework/boogie.shard_1.bpl | 7629 +++++++++++++++++ .../legacy-move-compiler/src/expansion/ast.rs | 54 +- .../src/expansion/translate.rs | 50 +- .../legacy-move-compiler/src/parser/ast.rs | 48 +- .../legacy-move-compiler/src/parser/lexer.rs | 6 +- .../legacy-move-compiler/src/parser/syntax.rs | 90 +- .../file_format_generator/module_generator.rs | 12 + third_party/move/move-compiler-v2/src/fuzz.rs | 93 + third_party/move/move-compiler-v2/src/lib.rs | 1 + .../move/move-compiler-v2/src/lint_common.rs | 17 + .../move/move-compiler-v2/src/plan_builder.rs | 525 +- .../tests/unit_test/test/fuzz_constraints.exp | 57 + .../unit_test/test/fuzz_constraints.move | 27 + .../tests/unit_test/test/fuzz_implicit.exp | 25 + .../tests/unit_test/test/fuzz_implicit.move | 14 + .../tests/unit_test/test/fuzz_matrix.exp | 2 + .../tests/unit_test/test/fuzz_matrix.move | 12 + .../test/fuzz_mix_assign_constraint.exp | 29 + .../test/fuzz_mix_assign_constraint.move | 8 + third_party/move/move-model/src/ast.rs | 23 +- .../move-model/src/builder/module_builder.rs | 160 +- .../move-prover/move-docgen/src/docgen.rs | 75 +- 22 files changed, 8791 insertions(+), 166 deletions(-) create mode 100644 aptos-move/framework/aptos-framework/boogie.shard_1.bpl create mode 100644 third_party/move/move-compiler-v2/src/fuzz.rs create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.move create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.move create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.move diff --git a/aptos-move/framework/aptos-framework/boogie.shard_1.bpl b/aptos-move/framework/aptos-framework/boogie.shard_1.bpl new file mode 100644 index 00000000000..88ea4f0c93f --- /dev/null +++ b/aptos-move/framework/aptos-framework/boogie.shard_1.bpl @@ -0,0 +1,7629 @@ + +// ** Expanded prelude + +// Copyright (c) The Diem Core Contributors +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +// Basic theory for vectors using arrays. This version of vectors is not extensional. + +datatype Vec { + Vec(v: [int]T, l: int) +} + +function {:builtin "MapConst"} MapConstVec(T): [int]T; +function DefaultVecElem(): T; +function {:inline} DefaultVecMap(): [int]T { MapConstVec(DefaultVecElem()) } + +function {:inline} EmptyVec(): Vec T { + Vec(DefaultVecMap(), 0) +} + +function {:inline} MakeVec1(v: T): Vec T { + Vec(DefaultVecMap()[0 := v], 1) +} + +function {:inline} MakeVec2(v1: T, v2: T): Vec T { + Vec(DefaultVecMap()[0 := v1][1 := v2], 2) +} + +function {:inline} MakeVec3(v1: T, v2: T, v3: T): Vec T { + Vec(DefaultVecMap()[0 := v1][1 := v2][2 := v3], 3) +} + +function {:inline} MakeVec4(v1: T, v2: T, v3: T, v4: T): Vec T { + Vec(DefaultVecMap()[0 := v1][1 := v2][2 := v3][3 := v4], 4) +} + +function {:inline} ExtendVec(v: Vec T, elem: T): Vec T { + (var l := v->l; + Vec(v->v[l := elem], l + 1)) +} + +function {:inline} ReadVec(v: Vec T, i: int): T { + v->v[i] +} + +function {:inline} LenVec(v: Vec T): int { + v->l +} + +function {:inline} IsEmptyVec(v: Vec T): bool { + v->l == 0 +} + +function {:inline} RemoveVec(v: Vec T): Vec T { + (var l := v->l - 1; + Vec(v->v[l := DefaultVecElem()], l)) +} + +function {:inline} RemoveAtVec(v: Vec T, i: int): Vec T { + (var l := v->l - 1; + Vec( + (lambda j: int :: + if j >= 0 && j < l then + if j < i then v->v[j] else v->v[j+1] + else DefaultVecElem()), + l)) +} + +function {:inline} ConcatVec(v1: Vec T, v2: Vec T): Vec T { + (var l1, m1, l2, m2 := v1->l, v1->v, v2->l, v2->v; + Vec( + (lambda i: int :: + if i >= 0 && i < l1 + l2 then + if i < l1 then m1[i] else m2[i - l1] + else DefaultVecElem()), + l1 + l2)) +} + +function {:inline} ReverseVec(v: Vec T): Vec T { + (var l := v->l; + Vec( + (lambda i: int :: if 0 <= i && i < l then v->v[l - i - 1] else DefaultVecElem()), + l)) +} + +function {:inline} SliceVec(v: Vec T, i: int, j: int): Vec T { + (var m := v->v; + Vec( + (lambda k:int :: + if 0 <= k && k < j - i then + m[i + k] + else + DefaultVecElem()), + (if j - i < 0 then 0 else j - i))) +} + + +function {:inline} UpdateVec(v: Vec T, i: int, elem: T): Vec T { + Vec(v->v[i := elem], v->l) +} + +function {:inline} SwapVec(v: Vec T, i: int, j: int): Vec T { + (var m := v->v; + Vec(m[i := m[j]][j := m[i]], v->l)) +} + +function {:inline} ContainsVec(v: Vec T, e: T): bool { + (var l := v->l; + (exists i: int :: InRangeVec(v, i) && v->v[i] == e)) +} + +function IndexOfVec(v: Vec T, e: T): int; +axiom {:ctor "Vec"} (forall v: Vec T, e: T :: {IndexOfVec(v, e)} + (var i := IndexOfVec(v,e); + if (!ContainsVec(v, e)) then i == -1 + else InRangeVec(v, i) && ReadVec(v, i) == e && + (forall j: int :: j >= 0 && j < i ==> ReadVec(v, j) != e))); + +// This function should stay non-inlined as it guards many quantifiers +// over vectors. It appears important to have this uninterpreted for +// quantifier triggering. +function InRangeVec(v: Vec T, i: int): bool { + i >= 0 && i < LenVec(v) +} + +// Copyright (c) The Diem Core Contributors +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +// Boogie model for multisets, based on Boogie arrays. This theory assumes extensional equality for element types. + +datatype Multiset { + Multiset(v: [T]int, l: int) +} + +function {:builtin "MapConst"} MapConstMultiset(l: int): [T]int; + +function {:inline} EmptyMultiset(): Multiset T { + Multiset(MapConstMultiset(0), 0) +} + +function {:inline} LenMultiset(s: Multiset T): int { + s->l +} + +function {:inline} ExtendMultiset(s: Multiset T, v: T): Multiset T { + (var len := s->l; + (var cnt := s->v[v]; + Multiset(s->v[v := (cnt + 1)], len + 1))) +} + +// This function returns (s1 - s2). This function assumes that s2 is a subset of s1. +function {:inline} SubtractMultiset(s1: Multiset T, s2: Multiset T): Multiset T { + (var len1 := s1->l; + (var len2 := s2->l; + Multiset((lambda v:T :: s1->v[v]-s2->v[v]), len1-len2))) +} + +function {:inline} IsEmptyMultiset(s: Multiset T): bool { + (s->l == 0) && + (forall v: T :: s->v[v] == 0) +} + +function {:inline} IsSubsetMultiset(s1: Multiset T, s2: Multiset T): bool { + (s1->l <= s2->l) && + (forall v: T :: s1->v[v] <= s2->v[v]) +} + +function {:inline} ContainsMultiset(s: Multiset T, v: T): bool { + s->v[v] > 0 +} + +// Copyright (c) The Diem Core Contributors +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +// Theory for tables. + +// v is the SMT array holding the key-value assignment. e is an array which +// independently determines whether a key is valid or not. l is the length. +// +// Note that even though the program cannot reflect over existence of a key, +// we want the specification to be able to do this, so it can express +// verification conditions like "key has been inserted". +datatype Table { + Table(v: [K]V, e: [K]bool, l: int) +} + +// Functions for default SMT arrays. For the table values, we don't care and +// use an uninterpreted function. +function DefaultTableArray(): [K]V; +function DefaultTableKeyExistsArray(): [K]bool; +axiom DefaultTableKeyExistsArray() == (lambda i: int :: false); + +function {:inline} EmptyTable(): Table K V { + Table(DefaultTableArray(), DefaultTableKeyExistsArray(), 0) +} + +function {:inline} GetTable(t: Table K V, k: K): V { + // Notice we do not check whether key is in the table. The result is undetermined if it is not. + t->v[k] +} + +function {:inline} LenTable(t: Table K V): int { + t->l +} + + +function {:inline} ContainsTable(t: Table K V, k: K): bool { + t->e[k] +} + +function {:inline} UpdateTable(t: Table K V, k: K, v: V): Table K V { + Table(t->v[k := v], t->e, t->l) +} + +function {:inline} AddTable(t: Table K V, k: K, v: V): Table K V { + // This function has an undetermined result if the key is already in the table + // (all specification functions have this "partial definiteness" behavior). Thus we can + // just increment the length. + Table(t->v[k := v], t->e[k := true], t->l + 1) +} + +function {:inline} RemoveTable(t: Table K V, k: K): Table K V { + // Similar as above, we only need to consider the case where the key is in the table. + Table(t->v, t->e[k := false], t->l - 1) +} + +axiom {:ctor "Table"} (forall t: Table K V :: {LenTable(t)} + (exists k: K :: {ContainsTable(t, k)} ContainsTable(t, k)) ==> LenTable(t) >= 1 +); +// TODO: we might want to encoder a stronger property that the length of table +// must be more than N given a set of N items. Currently we don't see a need here +// and the above axiom seems to be sufficient. +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +// ================================================================================== +// Native object::exists_at + +// ================================================================================== +// Intrinsic implementation of aggregator and aggregator factory + +datatype $1_aggregator_Aggregator { + $1_aggregator_Aggregator($handle: int, $key: int, $limit: int, $val: int) +} +function {:inline} $Update'$1_aggregator_Aggregator'_handle(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { + $1_aggregator_Aggregator(x, s->$key, s->$limit, s->$val) +} +function {:inline} $Update'$1_aggregator_Aggregator'_key(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { + $1_aggregator_Aggregator(s->$handle, x, s->$limit, s->$val) +} +function {:inline} $Update'$1_aggregator_Aggregator'_limit(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { + $1_aggregator_Aggregator(s->$handle, s->$key, x, s->$val) +} +function {:inline} $Update'$1_aggregator_Aggregator'_val(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { + $1_aggregator_Aggregator(s->$handle, s->$key, s->$limit, x) +} +function $IsValid'$1_aggregator_Aggregator'(s: $1_aggregator_Aggregator): bool { + $IsValid'address'(s->$handle) + && $IsValid'address'(s->$key) + && $IsValid'u128'(s->$limit) + && $IsValid'u128'(s->$val) +} +function {:inline} $IsEqual'$1_aggregator_Aggregator'(s1: $1_aggregator_Aggregator, s2: $1_aggregator_Aggregator): bool { + s1 == s2 +} +function {:inline} $1_aggregator_spec_get_limit(s: $1_aggregator_Aggregator): int { + s->$limit +} +function {:inline} $1_aggregator_limit(s: $1_aggregator_Aggregator): int { + s->$limit +} +procedure {:inline 1} $1_aggregator_limit(s: $1_aggregator_Aggregator) returns (res: int) { + res := s->$limit; + return; +} +function {:inline} $1_aggregator_spec_get_handle(s: $1_aggregator_Aggregator): int { + s->$handle +} +function {:inline} $1_aggregator_spec_get_key(s: $1_aggregator_Aggregator): int { + s->$key +} +function {:inline} $1_aggregator_spec_get_val(s: $1_aggregator_Aggregator): int { + s->$val +} + +function $1_aggregator_spec_read(agg: $1_aggregator_Aggregator): int { + $1_aggregator_spec_get_val(agg) +} + +function $1_aggregator_spec_aggregator_set_val(agg: $1_aggregator_Aggregator, val: int): $1_aggregator_Aggregator { + $Update'$1_aggregator_Aggregator'_val(agg, val) +} + +function $1_aggregator_spec_aggregator_get_val(agg: $1_aggregator_Aggregator): int { + $1_aggregator_spec_get_val(agg) +} + +function $1_aggregator_factory_spec_new_aggregator(limit: int) : $1_aggregator_Aggregator; + +axiom (forall limit: int :: {$1_aggregator_factory_spec_new_aggregator(limit)} + (var agg := $1_aggregator_factory_spec_new_aggregator(limit); + $1_aggregator_spec_get_limit(agg) == limit)); + +axiom (forall limit: int :: {$1_aggregator_factory_spec_new_aggregator(limit)} + (var agg := $1_aggregator_factory_spec_new_aggregator(limit); + $1_aggregator_spec_aggregator_get_val(agg) == 0)); + +// ================================================================================== +// Native for function_info + +procedure $1_function_info_is_identifier(s: Vec int) returns (res: bool); + + + +// Uninterpreted function for all types + +function $Arbitrary_value_of'#0'(): #0; + +function $Arbitrary_value_of'$1_account_Account'(): $1_account_Account; + +function $Arbitrary_value_of'$1_account_CapabilityOffer'$1_account_RotationCapability''(): $1_account_CapabilityOffer'$1_account_RotationCapability'; + +function $Arbitrary_value_of'$1_account_CapabilityOffer'$1_account_SignerCapability''(): $1_account_CapabilityOffer'$1_account_SignerCapability'; + +function $Arbitrary_value_of'$1_account_SignerCapability'(): $1_account_SignerCapability; + +function $Arbitrary_value_of'$1_chain_status_GenesisEndMarker'(): $1_chain_status_GenesisEndMarker; + +function $Arbitrary_value_of'$1_event_EventHandle'$1_account_CoinRegisterEvent''(): $1_event_EventHandle'$1_account_CoinRegisterEvent'; + +function $Arbitrary_value_of'$1_event_EventHandle'$1_account_KeyRotationEvent''(): $1_event_EventHandle'$1_account_KeyRotationEvent'; + +function $Arbitrary_value_of'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'; + +function $Arbitrary_value_of'$1_features_Features'(): $1_features_Features; + +function $Arbitrary_value_of'$1_guid_GUID'(): $1_guid_GUID; + +function $Arbitrary_value_of'$1_guid_ID'(): $1_guid_ID; + +function $Arbitrary_value_of'$1_option_Option'address''(): $1_option_Option'address'; + +function $Arbitrary_value_of'$1_permissioned_signer_GrantedPermissionHandles'(): $1_permissioned_signer_GrantedPermissionHandles; + +function $Arbitrary_value_of'$1_reconfiguration_Configuration'(): $1_reconfiguration_Configuration; + +function $Arbitrary_value_of'$1_timelock_AddCreators'(): $1_timelock_AddCreators; + +function $Arbitrary_value_of'$1_timelock_AddExecutors'(): $1_timelock_AddExecutors; + +function $Arbitrary_value_of'$1_timelock_CancelTransaction'(): $1_timelock_CancelTransaction; + +function $Arbitrary_value_of'$1_timelock_CreateTransaction'(): $1_timelock_CreateTransaction; + +function $Arbitrary_value_of'$1_timelock_RemoveCreators'(): $1_timelock_RemoveCreators; + +function $Arbitrary_value_of'$1_timelock_RemoveExecutors'(): $1_timelock_RemoveExecutors; + +function $Arbitrary_value_of'$1_timelock_TimelockAccount'(): $1_timelock_TimelockAccount; + +function $Arbitrary_value_of'$1_timelock_TimelockTransaction'(): $1_timelock_TimelockTransaction; + +function $Arbitrary_value_of'$1_timelock_UpdateMinNumSecondsExecute'(): $1_timelock_UpdateMinNumSecondsExecute; + +function $Arbitrary_value_of'$1_timestamp_CurrentTimeMicroseconds'(): $1_timestamp_CurrentTimeMicroseconds; + +function $Arbitrary_value_of'$1_type_info_TypeInfo'(): $1_type_info_TypeInfo; + +function $Arbitrary_value_of'signer'(): $signer; + +function $Arbitrary_value_of'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(): Table int ($1_timelock_TimelockTransaction); + +function $Arbitrary_value_of'vec'#0''(): Vec (#0); + +function $Arbitrary_value_of'vec'address''(): Vec (int); + +function $Arbitrary_value_of'vec'u8''(): Vec (int); + +function $Arbitrary_value_of'bool'(): bool; + +function $Arbitrary_value_of'address'(): int; + +function $Arbitrary_value_of'u256'(): int; + +function $Arbitrary_value_of'u64'(): int; + +function $Arbitrary_value_of'u8'(): int; + +function $Arbitrary_value_of'vec'bv8''(): Vec (bv8); + +function $Arbitrary_value_of'bv256'(): bv256; + +function $Arbitrary_value_of'bv64'(): bv64; + +function $Arbitrary_value_of'bv8'(): bv8; + + + +// ============================================================================================ +// Primitive Types + +const $MAX_U8: int; +axiom $MAX_U8 == 255; +const $MAX_U16: int; +axiom $MAX_U16 == 65535; +const $MAX_U32: int; +axiom $MAX_U32 == 4294967295; +const $MAX_U64: int; +axiom $MAX_U64 == 18446744073709551615; +const $MAX_U128: int; +axiom $MAX_U128 == 340282366920938463463374607431768211455; +const $MAX_U256: int; +axiom $MAX_U256 == 115792089237316195423570985008687907853269984665640564039457584007913129639935; + +// Templates for bitvector operations + +function {:bvbuiltin "bvand"} $And'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvor"} $Or'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvxor"} $Xor'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvadd"} $Add'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvsub"} $Sub'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvmul"} $Mul'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvudiv"} $Div'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvurem"} $Mod'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvshl"} $Shl'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvlshr"} $Shr'Bv8'(bv8,bv8) returns(bv8); +function {:bvbuiltin "bvult"} $Lt'Bv8'(bv8,bv8) returns(bool); +function {:bvbuiltin "bvule"} $Le'Bv8'(bv8,bv8) returns(bool); +function {:bvbuiltin "bvugt"} $Gt'Bv8'(bv8,bv8) returns(bool); +function {:bvbuiltin "bvuge"} $Ge'Bv8'(bv8,bv8) returns(bool); + +procedure {:inline 1} $AddBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if ($Lt'Bv8'($Add'Bv8'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Add'Bv8'(src1, src2); +} + +procedure {:inline 1} $AddBv8_unchecked(src1: bv8, src2: bv8) returns (dst: bv8) +{ + dst := $Add'Bv8'(src1, src2); +} + +procedure {:inline 1} $SubBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if ($Lt'Bv8'(src1, src2)) { + call $ExecFailureAbort(); + return; + } + dst := $Sub'Bv8'(src1, src2); +} + +procedure {:inline 1} $MulBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if ($Lt'Bv8'($Mul'Bv8'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Mul'Bv8'(src1, src2); +} + +procedure {:inline 1} $DivBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if (src2 == 0bv8) { + call $ExecFailureAbort(); + return; + } + dst := $Div'Bv8'(src1, src2); +} + +procedure {:inline 1} $ModBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if (src2 == 0bv8) { + call $ExecFailureAbort(); + return; + } + dst := $Mod'Bv8'(src1, src2); +} + +procedure {:inline 1} $AndBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + dst := $And'Bv8'(src1,src2); +} + +procedure {:inline 1} $OrBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + dst := $Or'Bv8'(src1,src2); +} + +procedure {:inline 1} $XorBv8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + dst := $Xor'Bv8'(src1,src2); +} + +procedure {:inline 1} $LtBv8(src1: bv8, src2: bv8) returns (dst: bool) +{ + dst := $Lt'Bv8'(src1,src2); +} + +procedure {:inline 1} $LeBv8(src1: bv8, src2: bv8) returns (dst: bool) +{ + dst := $Le'Bv8'(src1,src2); +} + +procedure {:inline 1} $GtBv8(src1: bv8, src2: bv8) returns (dst: bool) +{ + dst := $Gt'Bv8'(src1,src2); +} + +procedure {:inline 1} $GeBv8(src1: bv8, src2: bv8) returns (dst: bool) +{ + dst := $Ge'Bv8'(src1,src2); +} + +function $IsValid'bv8'(v: bv8): bool { + $Ge'Bv8'(v,0bv8) && $Le'Bv8'(v,255bv8) +} + +function {:inline} $IsEqual'bv8'(x: bv8, y: bv8): bool { + x == y +} + +procedure {:inline 1} $int2bv8(src: int) returns (dst: bv8) +{ + if (src > 255) { + call $ExecFailureAbort(); + return; + } + dst := $int2bv.8(src); +} + +procedure {:inline 1} $bv2int8(src: bv8) returns (dst: int) +{ + dst := $bv2int.8(src); +} + +function {:builtin "(_ int2bv 8)"} $int2bv.8(i: int) returns (bv8); +function {:builtin "bv2nat"} $bv2int.8(i: bv8) returns (int); + +function {:bvbuiltin "bvand"} $And'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvor"} $Or'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvxor"} $Xor'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvadd"} $Add'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvsub"} $Sub'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvmul"} $Mul'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvudiv"} $Div'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvurem"} $Mod'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvshl"} $Shl'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvlshr"} $Shr'Bv16'(bv16,bv16) returns(bv16); +function {:bvbuiltin "bvult"} $Lt'Bv16'(bv16,bv16) returns(bool); +function {:bvbuiltin "bvule"} $Le'Bv16'(bv16,bv16) returns(bool); +function {:bvbuiltin "bvugt"} $Gt'Bv16'(bv16,bv16) returns(bool); +function {:bvbuiltin "bvuge"} $Ge'Bv16'(bv16,bv16) returns(bool); + +procedure {:inline 1} $AddBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if ($Lt'Bv16'($Add'Bv16'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Add'Bv16'(src1, src2); +} + +procedure {:inline 1} $AddBv16_unchecked(src1: bv16, src2: bv16) returns (dst: bv16) +{ + dst := $Add'Bv16'(src1, src2); +} + +procedure {:inline 1} $SubBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if ($Lt'Bv16'(src1, src2)) { + call $ExecFailureAbort(); + return; + } + dst := $Sub'Bv16'(src1, src2); +} + +procedure {:inline 1} $MulBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if ($Lt'Bv16'($Mul'Bv16'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Mul'Bv16'(src1, src2); +} + +procedure {:inline 1} $DivBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if (src2 == 0bv16) { + call $ExecFailureAbort(); + return; + } + dst := $Div'Bv16'(src1, src2); +} + +procedure {:inline 1} $ModBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if (src2 == 0bv16) { + call $ExecFailureAbort(); + return; + } + dst := $Mod'Bv16'(src1, src2); +} + +procedure {:inline 1} $AndBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + dst := $And'Bv16'(src1,src2); +} + +procedure {:inline 1} $OrBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + dst := $Or'Bv16'(src1,src2); +} + +procedure {:inline 1} $XorBv16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + dst := $Xor'Bv16'(src1,src2); +} + +procedure {:inline 1} $LtBv16(src1: bv16, src2: bv16) returns (dst: bool) +{ + dst := $Lt'Bv16'(src1,src2); +} + +procedure {:inline 1} $LeBv16(src1: bv16, src2: bv16) returns (dst: bool) +{ + dst := $Le'Bv16'(src1,src2); +} + +procedure {:inline 1} $GtBv16(src1: bv16, src2: bv16) returns (dst: bool) +{ + dst := $Gt'Bv16'(src1,src2); +} + +procedure {:inline 1} $GeBv16(src1: bv16, src2: bv16) returns (dst: bool) +{ + dst := $Ge'Bv16'(src1,src2); +} + +function $IsValid'bv16'(v: bv16): bool { + $Ge'Bv16'(v,0bv16) && $Le'Bv16'(v,65535bv16) +} + +function {:inline} $IsEqual'bv16'(x: bv16, y: bv16): bool { + x == y +} + +procedure {:inline 1} $int2bv16(src: int) returns (dst: bv16) +{ + if (src > 65535) { + call $ExecFailureAbort(); + return; + } + dst := $int2bv.16(src); +} + +procedure {:inline 1} $bv2int16(src: bv16) returns (dst: int) +{ + dst := $bv2int.16(src); +} + +function {:builtin "(_ int2bv 16)"} $int2bv.16(i: int) returns (bv16); +function {:builtin "bv2nat"} $bv2int.16(i: bv16) returns (int); + +function {:bvbuiltin "bvand"} $And'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvor"} $Or'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvxor"} $Xor'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvadd"} $Add'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvsub"} $Sub'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvmul"} $Mul'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvudiv"} $Div'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvurem"} $Mod'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvshl"} $Shl'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvlshr"} $Shr'Bv32'(bv32,bv32) returns(bv32); +function {:bvbuiltin "bvult"} $Lt'Bv32'(bv32,bv32) returns(bool); +function {:bvbuiltin "bvule"} $Le'Bv32'(bv32,bv32) returns(bool); +function {:bvbuiltin "bvugt"} $Gt'Bv32'(bv32,bv32) returns(bool); +function {:bvbuiltin "bvuge"} $Ge'Bv32'(bv32,bv32) returns(bool); + +procedure {:inline 1} $AddBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if ($Lt'Bv32'($Add'Bv32'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Add'Bv32'(src1, src2); +} + +procedure {:inline 1} $AddBv32_unchecked(src1: bv32, src2: bv32) returns (dst: bv32) +{ + dst := $Add'Bv32'(src1, src2); +} + +procedure {:inline 1} $SubBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if ($Lt'Bv32'(src1, src2)) { + call $ExecFailureAbort(); + return; + } + dst := $Sub'Bv32'(src1, src2); +} + +procedure {:inline 1} $MulBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if ($Lt'Bv32'($Mul'Bv32'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Mul'Bv32'(src1, src2); +} + +procedure {:inline 1} $DivBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if (src2 == 0bv32) { + call $ExecFailureAbort(); + return; + } + dst := $Div'Bv32'(src1, src2); +} + +procedure {:inline 1} $ModBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if (src2 == 0bv32) { + call $ExecFailureAbort(); + return; + } + dst := $Mod'Bv32'(src1, src2); +} + +procedure {:inline 1} $AndBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + dst := $And'Bv32'(src1,src2); +} + +procedure {:inline 1} $OrBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + dst := $Or'Bv32'(src1,src2); +} + +procedure {:inline 1} $XorBv32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + dst := $Xor'Bv32'(src1,src2); +} + +procedure {:inline 1} $LtBv32(src1: bv32, src2: bv32) returns (dst: bool) +{ + dst := $Lt'Bv32'(src1,src2); +} + +procedure {:inline 1} $LeBv32(src1: bv32, src2: bv32) returns (dst: bool) +{ + dst := $Le'Bv32'(src1,src2); +} + +procedure {:inline 1} $GtBv32(src1: bv32, src2: bv32) returns (dst: bool) +{ + dst := $Gt'Bv32'(src1,src2); +} + +procedure {:inline 1} $GeBv32(src1: bv32, src2: bv32) returns (dst: bool) +{ + dst := $Ge'Bv32'(src1,src2); +} + +function $IsValid'bv32'(v: bv32): bool { + $Ge'Bv32'(v,0bv32) && $Le'Bv32'(v,2147483647bv32) +} + +function {:inline} $IsEqual'bv32'(x: bv32, y: bv32): bool { + x == y +} + +procedure {:inline 1} $int2bv32(src: int) returns (dst: bv32) +{ + if (src > 2147483647) { + call $ExecFailureAbort(); + return; + } + dst := $int2bv.32(src); +} + +procedure {:inline 1} $bv2int32(src: bv32) returns (dst: int) +{ + dst := $bv2int.32(src); +} + +function {:builtin "(_ int2bv 32)"} $int2bv.32(i: int) returns (bv32); +function {:builtin "bv2nat"} $bv2int.32(i: bv32) returns (int); + +function {:bvbuiltin "bvand"} $And'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvor"} $Or'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvxor"} $Xor'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvadd"} $Add'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvsub"} $Sub'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvmul"} $Mul'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvudiv"} $Div'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvurem"} $Mod'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvshl"} $Shl'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvlshr"} $Shr'Bv64'(bv64,bv64) returns(bv64); +function {:bvbuiltin "bvult"} $Lt'Bv64'(bv64,bv64) returns(bool); +function {:bvbuiltin "bvule"} $Le'Bv64'(bv64,bv64) returns(bool); +function {:bvbuiltin "bvugt"} $Gt'Bv64'(bv64,bv64) returns(bool); +function {:bvbuiltin "bvuge"} $Ge'Bv64'(bv64,bv64) returns(bool); + +procedure {:inline 1} $AddBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if ($Lt'Bv64'($Add'Bv64'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Add'Bv64'(src1, src2); +} + +procedure {:inline 1} $AddBv64_unchecked(src1: bv64, src2: bv64) returns (dst: bv64) +{ + dst := $Add'Bv64'(src1, src2); +} + +procedure {:inline 1} $SubBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if ($Lt'Bv64'(src1, src2)) { + call $ExecFailureAbort(); + return; + } + dst := $Sub'Bv64'(src1, src2); +} + +procedure {:inline 1} $MulBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if ($Lt'Bv64'($Mul'Bv64'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Mul'Bv64'(src1, src2); +} + +procedure {:inline 1} $DivBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if (src2 == 0bv64) { + call $ExecFailureAbort(); + return; + } + dst := $Div'Bv64'(src1, src2); +} + +procedure {:inline 1} $ModBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if (src2 == 0bv64) { + call $ExecFailureAbort(); + return; + } + dst := $Mod'Bv64'(src1, src2); +} + +procedure {:inline 1} $AndBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + dst := $And'Bv64'(src1,src2); +} + +procedure {:inline 1} $OrBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + dst := $Or'Bv64'(src1,src2); +} + +procedure {:inline 1} $XorBv64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + dst := $Xor'Bv64'(src1,src2); +} + +procedure {:inline 1} $LtBv64(src1: bv64, src2: bv64) returns (dst: bool) +{ + dst := $Lt'Bv64'(src1,src2); +} + +procedure {:inline 1} $LeBv64(src1: bv64, src2: bv64) returns (dst: bool) +{ + dst := $Le'Bv64'(src1,src2); +} + +procedure {:inline 1} $GtBv64(src1: bv64, src2: bv64) returns (dst: bool) +{ + dst := $Gt'Bv64'(src1,src2); +} + +procedure {:inline 1} $GeBv64(src1: bv64, src2: bv64) returns (dst: bool) +{ + dst := $Ge'Bv64'(src1,src2); +} + +function $IsValid'bv64'(v: bv64): bool { + $Ge'Bv64'(v,0bv64) && $Le'Bv64'(v,18446744073709551615bv64) +} + +function {:inline} $IsEqual'bv64'(x: bv64, y: bv64): bool { + x == y +} + +procedure {:inline 1} $int2bv64(src: int) returns (dst: bv64) +{ + if (src > 18446744073709551615) { + call $ExecFailureAbort(); + return; + } + dst := $int2bv.64(src); +} + +procedure {:inline 1} $bv2int64(src: bv64) returns (dst: int) +{ + dst := $bv2int.64(src); +} + +function {:builtin "(_ int2bv 64)"} $int2bv.64(i: int) returns (bv64); +function {:builtin "bv2nat"} $bv2int.64(i: bv64) returns (int); + +function {:bvbuiltin "bvand"} $And'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvor"} $Or'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvxor"} $Xor'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvadd"} $Add'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvsub"} $Sub'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvmul"} $Mul'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvudiv"} $Div'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvurem"} $Mod'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvshl"} $Shl'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvlshr"} $Shr'Bv128'(bv128,bv128) returns(bv128); +function {:bvbuiltin "bvult"} $Lt'Bv128'(bv128,bv128) returns(bool); +function {:bvbuiltin "bvule"} $Le'Bv128'(bv128,bv128) returns(bool); +function {:bvbuiltin "bvugt"} $Gt'Bv128'(bv128,bv128) returns(bool); +function {:bvbuiltin "bvuge"} $Ge'Bv128'(bv128,bv128) returns(bool); + +procedure {:inline 1} $AddBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if ($Lt'Bv128'($Add'Bv128'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Add'Bv128'(src1, src2); +} + +procedure {:inline 1} $AddBv128_unchecked(src1: bv128, src2: bv128) returns (dst: bv128) +{ + dst := $Add'Bv128'(src1, src2); +} + +procedure {:inline 1} $SubBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if ($Lt'Bv128'(src1, src2)) { + call $ExecFailureAbort(); + return; + } + dst := $Sub'Bv128'(src1, src2); +} + +procedure {:inline 1} $MulBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if ($Lt'Bv128'($Mul'Bv128'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Mul'Bv128'(src1, src2); +} + +procedure {:inline 1} $DivBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if (src2 == 0bv128) { + call $ExecFailureAbort(); + return; + } + dst := $Div'Bv128'(src1, src2); +} + +procedure {:inline 1} $ModBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if (src2 == 0bv128) { + call $ExecFailureAbort(); + return; + } + dst := $Mod'Bv128'(src1, src2); +} + +procedure {:inline 1} $AndBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + dst := $And'Bv128'(src1,src2); +} + +procedure {:inline 1} $OrBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + dst := $Or'Bv128'(src1,src2); +} + +procedure {:inline 1} $XorBv128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + dst := $Xor'Bv128'(src1,src2); +} + +procedure {:inline 1} $LtBv128(src1: bv128, src2: bv128) returns (dst: bool) +{ + dst := $Lt'Bv128'(src1,src2); +} + +procedure {:inline 1} $LeBv128(src1: bv128, src2: bv128) returns (dst: bool) +{ + dst := $Le'Bv128'(src1,src2); +} + +procedure {:inline 1} $GtBv128(src1: bv128, src2: bv128) returns (dst: bool) +{ + dst := $Gt'Bv128'(src1,src2); +} + +procedure {:inline 1} $GeBv128(src1: bv128, src2: bv128) returns (dst: bool) +{ + dst := $Ge'Bv128'(src1,src2); +} + +function $IsValid'bv128'(v: bv128): bool { + $Ge'Bv128'(v,0bv128) && $Le'Bv128'(v,340282366920938463463374607431768211455bv128) +} + +function {:inline} $IsEqual'bv128'(x: bv128, y: bv128): bool { + x == y +} + +procedure {:inline 1} $int2bv128(src: int) returns (dst: bv128) +{ + if (src > 340282366920938463463374607431768211455) { + call $ExecFailureAbort(); + return; + } + dst := $int2bv.128(src); +} + +procedure {:inline 1} $bv2int128(src: bv128) returns (dst: int) +{ + dst := $bv2int.128(src); +} + +function {:builtin "(_ int2bv 128)"} $int2bv.128(i: int) returns (bv128); +function {:builtin "bv2nat"} $bv2int.128(i: bv128) returns (int); + +function {:bvbuiltin "bvand"} $And'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvor"} $Or'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvxor"} $Xor'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvadd"} $Add'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvsub"} $Sub'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvmul"} $Mul'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvudiv"} $Div'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvurem"} $Mod'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvshl"} $Shl'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvlshr"} $Shr'Bv256'(bv256,bv256) returns(bv256); +function {:bvbuiltin "bvult"} $Lt'Bv256'(bv256,bv256) returns(bool); +function {:bvbuiltin "bvule"} $Le'Bv256'(bv256,bv256) returns(bool); +function {:bvbuiltin "bvugt"} $Gt'Bv256'(bv256,bv256) returns(bool); +function {:bvbuiltin "bvuge"} $Ge'Bv256'(bv256,bv256) returns(bool); + +procedure {:inline 1} $AddBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if ($Lt'Bv256'($Add'Bv256'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Add'Bv256'(src1, src2); +} + +procedure {:inline 1} $AddBv256_unchecked(src1: bv256, src2: bv256) returns (dst: bv256) +{ + dst := $Add'Bv256'(src1, src2); +} + +procedure {:inline 1} $SubBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if ($Lt'Bv256'(src1, src2)) { + call $ExecFailureAbort(); + return; + } + dst := $Sub'Bv256'(src1, src2); +} + +procedure {:inline 1} $MulBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if ($Lt'Bv256'($Mul'Bv256'(src1, src2), src1)) { + call $ExecFailureAbort(); + return; + } + dst := $Mul'Bv256'(src1, src2); +} + +procedure {:inline 1} $DivBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if (src2 == 0bv256) { + call $ExecFailureAbort(); + return; + } + dst := $Div'Bv256'(src1, src2); +} + +procedure {:inline 1} $ModBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if (src2 == 0bv256) { + call $ExecFailureAbort(); + return; + } + dst := $Mod'Bv256'(src1, src2); +} + +procedure {:inline 1} $AndBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + dst := $And'Bv256'(src1,src2); +} + +procedure {:inline 1} $OrBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + dst := $Or'Bv256'(src1,src2); +} + +procedure {:inline 1} $XorBv256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + dst := $Xor'Bv256'(src1,src2); +} + +procedure {:inline 1} $LtBv256(src1: bv256, src2: bv256) returns (dst: bool) +{ + dst := $Lt'Bv256'(src1,src2); +} + +procedure {:inline 1} $LeBv256(src1: bv256, src2: bv256) returns (dst: bool) +{ + dst := $Le'Bv256'(src1,src2); +} + +procedure {:inline 1} $GtBv256(src1: bv256, src2: bv256) returns (dst: bool) +{ + dst := $Gt'Bv256'(src1,src2); +} + +procedure {:inline 1} $GeBv256(src1: bv256, src2: bv256) returns (dst: bool) +{ + dst := $Ge'Bv256'(src1,src2); +} + +function $IsValid'bv256'(v: bv256): bool { + $Ge'Bv256'(v,0bv256) && $Le'Bv256'(v,115792089237316195423570985008687907853269984665640564039457584007913129639935bv256) +} + +function {:inline} $IsEqual'bv256'(x: bv256, y: bv256): bool { + x == y +} + +procedure {:inline 1} $int2bv256(src: int) returns (dst: bv256) +{ + if (src > 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + call $ExecFailureAbort(); + return; + } + dst := $int2bv.256(src); +} + +procedure {:inline 1} $bv2int256(src: bv256) returns (dst: int) +{ + dst := $bv2int.256(src); +} + +function {:builtin "(_ int2bv 256)"} $int2bv.256(i: int) returns (bv256); +function {:builtin "bv2nat"} $bv2int.256(i: bv256) returns (int); + +datatype $Range { + $Range(lb: int, ub: int) +} + +function {:inline} $IsValid'bool'(v: bool): bool { + true +} + +function $IsValid'u8'(v: int): bool { + v >= 0 && v <= $MAX_U8 +} + +function $IsValid'u16'(v: int): bool { + v >= 0 && v <= $MAX_U16 +} + +function $IsValid'u32'(v: int): bool { + v >= 0 && v <= $MAX_U32 +} + +function $IsValid'u64'(v: int): bool { + v >= 0 && v <= $MAX_U64 +} + +function $IsValid'u128'(v: int): bool { + v >= 0 && v <= $MAX_U128 +} + +function $IsValid'u256'(v: int): bool { + v >= 0 && v <= $MAX_U256 +} + +function $IsValid'num'(v: int): bool { + true +} + +function $IsValid'address'(v: int): bool { + // TODO: restrict max to representable addresses? + v >= 0 +} + +function {:inline} $IsValidRange(r: $Range): bool { + $IsValid'u64'(r->lb) && $IsValid'u64'(r->ub) +} + +// Intentionally not inlined so it serves as a trigger in quantifiers. +function $InRange(r: $Range, i: int): bool { + r->lb <= i && i < r->ub +} + + +function {:inline} $IsEqual'u8'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'u16'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'u32'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'u64'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'u128'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'u256'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'num'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'address'(x: int, y: int): bool { + x == y +} + +function {:inline} $IsEqual'bool'(x: bool, y: bool): bool { + x == y +} + +// ============================================================================================ +// Memory + +datatype $Location { + // A global resource location within the statically known resource type's memory, + // where `a` is an address. + $Global(a: int), + // A local location. `i` is the unique index of the local. + $Local(i: int), + // The location of a reference outside of the verification scope, for example, a `&mut` parameter + // of the function being verified. References with these locations don't need to be written back + // when mutation ends. + $Param(i: int), + // The location of an uninitialized mutation. Using this to make sure that the location + // will not be equal to any valid mutation locations, i.e., $Local, $Global, or $Param. + $Uninitialized() +} + +// A mutable reference which also carries its current value. Since mutable references +// are single threaded in Move, we can keep them together and treat them as a value +// during mutation until the point they are stored back to their original location. +datatype $Mutation { + $Mutation(l: $Location, p: Vec int, v: T) +} + +// Representation of memory for a given type. +datatype $Memory { + $Memory(domain: [int]bool, contents: [int]T) +} + +function {:builtin "MapConst"} $ConstMemoryDomain(v: bool): [int]bool; +function {:builtin "MapConst"} $ConstMemoryContent(v: T): [int]T; +axiom $ConstMemoryDomain(false) == (lambda i: int :: false); +axiom $ConstMemoryDomain(true) == (lambda i: int :: true); + + +// Dereferences a mutation. +function {:inline} $Dereference(ref: $Mutation T): T { + ref->v +} + +// Update the value of a mutation. +function {:inline} $UpdateMutation(m: $Mutation T, v: T): $Mutation T { + $Mutation(m->l, m->p, v) +} + +function {:inline} $ChildMutation(m: $Mutation T1, offset: int, v: T2): $Mutation T2 { + $Mutation(m->l, ExtendVec(m->p, offset), v) +} + +// Return true if two mutations share the location and path +function {:inline} $IsSameMutation(parent: $Mutation T1, child: $Mutation T2 ): bool { + parent->l == child->l && parent->p == child->p +} + +// Return true if the mutation is a parent of a child which was derived with the given edge offset. This +// is used to implement write-back choices. +function {:inline} $IsParentMutation(parent: $Mutation T1, edge: int, child: $Mutation T2 ): bool { + parent->l == child->l && + (var pp := parent->p; + (var cp := child->p; + (var pl := LenVec(pp); + (var cl := LenVec(cp); + cl == pl + 1 && + (forall i: int:: i >= 0 && i < pl ==> ReadVec(pp, i) == ReadVec(cp, i)) && + $EdgeMatches(ReadVec(cp, pl), edge) + )))) +} + +// Return true if the mutation is a parent of a child, for hyper edge. +function {:inline} $IsParentMutationHyper(parent: $Mutation T1, hyper_edge: Vec int, child: $Mutation T2 ): bool { + parent->l == child->l && + (var pp := parent->p; + (var cp := child->p; + (var pl := LenVec(pp); + (var cl := LenVec(cp); + (var el := LenVec(hyper_edge); + cl == pl + el && + (forall i: int:: i >= 0 && i < pl ==> ReadVec(pp, i) == ReadVec(cp, i)) && + (forall i: int:: i >= 0 && i < el ==> $EdgeMatches(ReadVec(cp, pl + i), ReadVec(hyper_edge, i))) + ))))) +} + +function {:inline} $EdgeMatches(edge: int, edge_pattern: int): bool { + edge_pattern == -1 // wildcard + || edge_pattern == edge +} + + + +function {:inline} $SameLocation(m1: $Mutation T1, m2: $Mutation T2): bool { + m1->l == m2->l +} + +function {:inline} $HasGlobalLocation(m: $Mutation T): bool { + (m->l) is $Global +} + +function {:inline} $HasLocalLocation(m: $Mutation T, idx: int): bool { + m->l == $Local(idx) +} + +function {:inline} $GlobalLocationAddress(m: $Mutation T): int { + (m->l)->a +} + + + +// Tests whether resource exists. +function {:inline} $ResourceExists(m: $Memory T, addr: int): bool { + m->domain[addr] +} + +// Obtains Value of given resource. +function {:inline} $ResourceValue(m: $Memory T, addr: int): T { + m->contents[addr] +} + +// Update resource. +function {:inline} $ResourceUpdate(m: $Memory T, a: int, v: T): $Memory T { + $Memory(m->domain[a := true], m->contents[a := v]) +} + +// Remove resource. +function {:inline} $ResourceRemove(m: $Memory T, a: int): $Memory T { + $Memory(m->domain[a := false], m->contents) +} + +// Copies resource from memory s to m. +function {:inline} $ResourceCopy(m: $Memory T, s: $Memory T, a: int): $Memory T { + $Memory(m->domain[a := s->domain[a]], + m->contents[a := s->contents[a]]) +} + + + +// ============================================================================================ +// Abort Handling + +var $abort_flag: bool; +var $abort_code: int; + +function {:inline} $process_abort_code(code: int): int { + code +} + +const $EXEC_FAILURE_CODE: int; +axiom $EXEC_FAILURE_CODE == -1; + +// TODO(wrwg): currently we map aborts of native functions like those for vectors also to +// execution failure. This may need to be aligned with what the runtime actually does. + +procedure {:inline 1} $ExecFailureAbort() { + $abort_flag := true; + $abort_code := $EXEC_FAILURE_CODE; +} + +procedure {:inline 1} $Abort(code: int) { + $abort_flag := true; + $abort_code := code; +} + +function {:inline} $StdError(cat: int, reason: int): int { + reason * 256 + cat +} + +procedure {:inline 1} $InitVerification() { + // Set abort_flag to false, and havoc abort_code + $abort_flag := false; + havoc $abort_code; + // Initialize event store + call $InitEventStore(); +} + +// ============================================================================================ +// Instructions + + +procedure {:inline 1} $CastU8(src: int) returns (dst: int) +{ + if (src > $MAX_U8) { + call $ExecFailureAbort(); + return; + } + dst := src; +} + +procedure {:inline 1} $CastU16(src: int) returns (dst: int) +{ + if (src > $MAX_U16) { + call $ExecFailureAbort(); + return; + } + dst := src; +} + +procedure {:inline 1} $CastU32(src: int) returns (dst: int) +{ + if (src > $MAX_U32) { + call $ExecFailureAbort(); + return; + } + dst := src; +} + +procedure {:inline 1} $CastU64(src: int) returns (dst: int) +{ + if (src > $MAX_U64) { + call $ExecFailureAbort(); + return; + } + dst := src; +} + +procedure {:inline 1} $CastU128(src: int) returns (dst: int) +{ + if (src > $MAX_U128) { + call $ExecFailureAbort(); + return; + } + dst := src; +} + +procedure {:inline 1} $CastU256(src: int) returns (dst: int) +{ + if (src > $MAX_U256) { + call $ExecFailureAbort(); + return; + } + dst := src; +} + +procedure {:inline 1} $AddU8(src1: int, src2: int) returns (dst: int) +{ + if (src1 + src2 > $MAX_U8) { + call $ExecFailureAbort(); + return; + } + dst := src1 + src2; +} + +procedure {:inline 1} $AddU16(src1: int, src2: int) returns (dst: int) +{ + if (src1 + src2 > $MAX_U16) { + call $ExecFailureAbort(); + return; + } + dst := src1 + src2; +} + +procedure {:inline 1} $AddU16_unchecked(src1: int, src2: int) returns (dst: int) +{ + dst := src1 + src2; +} + +procedure {:inline 1} $AddU32(src1: int, src2: int) returns (dst: int) +{ + if (src1 + src2 > $MAX_U32) { + call $ExecFailureAbort(); + return; + } + dst := src1 + src2; +} + +procedure {:inline 1} $AddU32_unchecked(src1: int, src2: int) returns (dst: int) +{ + dst := src1 + src2; +} + +procedure {:inline 1} $AddU64(src1: int, src2: int) returns (dst: int) +{ + if (src1 + src2 > $MAX_U64) { + call $ExecFailureAbort(); + return; + } + dst := src1 + src2; +} + +procedure {:inline 1} $AddU64_unchecked(src1: int, src2: int) returns (dst: int) +{ + dst := src1 + src2; +} + +procedure {:inline 1} $AddU128(src1: int, src2: int) returns (dst: int) +{ + if (src1 + src2 > $MAX_U128) { + call $ExecFailureAbort(); + return; + } + dst := src1 + src2; +} + +procedure {:inline 1} $AddU128_unchecked(src1: int, src2: int) returns (dst: int) +{ + dst := src1 + src2; +} + +procedure {:inline 1} $AddU256(src1: int, src2: int) returns (dst: int) +{ + if (src1 + src2 > $MAX_U256) { + call $ExecFailureAbort(); + return; + } + dst := src1 + src2; +} + +procedure {:inline 1} $AddU256_unchecked(src1: int, src2: int) returns (dst: int) +{ + dst := src1 + src2; +} + +procedure {:inline 1} $Sub(src1: int, src2: int) returns (dst: int) +{ + if (src1 < src2) { + call $ExecFailureAbort(); + return; + } + dst := src1 - src2; +} + +// uninterpreted function to return an undefined value. +function $undefined_int(): int; + +// Recursive exponentiation function +// Undefined unless e >=0. $pow(0,0) is also undefined. +function $pow(n: int, e: int): int { + if n != 0 && e == 0 then 1 + else if e > 0 then n * $pow(n, e - 1) + else $undefined_int() +} + +function $shl(src1: int, p: int): int { + src1 * $pow(2, p) +} + +function $shlU8(src1: int, p: int): int { + (src1 * $pow(2, p)) mod 256 +} + +function $shlU16(src1: int, p: int): int { + (src1 * $pow(2, p)) mod 65536 +} + +function $shlU32(src1: int, p: int): int { + (src1 * $pow(2, p)) mod 4294967296 +} + +function $shlU64(src1: int, p: int): int { + (src1 * $pow(2, p)) mod 18446744073709551616 +} + +function $shlU128(src1: int, p: int): int { + (src1 * $pow(2, p)) mod 340282366920938463463374607431768211456 +} + +function $shlU256(src1: int, p: int): int { + (src1 * $pow(2, p)) mod 115792089237316195423570985008687907853269984665640564039457584007913129639936 +} + +function $shr(src1: int, p: int): int { + src1 div $pow(2, p) +} + +// We need to know the size of the destination in order to drop bits +// that have been shifted left more than that, so we have $ShlU8/16/32/64/128/256 +procedure {:inline 1} $ShlU8(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 8) { + call $ExecFailureAbort(); + return; + } + dst := $shlU8(src1, src2); +} + +// Template for cast and shift operations of bitvector types + +procedure {:inline 1} $CastBv8to8(src: bv8) returns (dst: bv8) +{ + dst := src; +} + + +function $castBv8to8(src: bv8) returns (bv8) +{ + src +} + + +function $shlBv8From8(src1: bv8, src2: bv8) returns (bv8) +{ + $Shl'Bv8'(src1, src2) +} + +procedure {:inline 1} $ShlBv8From8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if ($Ge'Bv8'(src2, 8bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv8'(src1, src2); +} + +function $shrBv8From8(src1: bv8, src2: bv8) returns (bv8) +{ + $Shr'Bv8'(src1, src2) +} + +procedure {:inline 1} $ShrBv8From8(src1: bv8, src2: bv8) returns (dst: bv8) +{ + if ($Ge'Bv8'(src2, 8bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv8'(src1, src2); +} + +procedure {:inline 1} $CastBv16to8(src: bv16) returns (dst: bv8) +{ + if ($Gt'Bv16'(src, 255bv16)) { + call $ExecFailureAbort(); + return; + } + dst := src[8:0]; +} + + + +function $shlBv8From16(src1: bv8, src2: bv16) returns (bv8) +{ + $Shl'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShlBv8From16(src1: bv8, src2: bv16) returns (dst: bv8) +{ + if ($Ge'Bv16'(src2, 8bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv8'(src1, src2[8:0]); +} + +function $shrBv8From16(src1: bv8, src2: bv16) returns (bv8) +{ + $Shr'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShrBv8From16(src1: bv8, src2: bv16) returns (dst: bv8) +{ + if ($Ge'Bv16'(src2, 8bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv8'(src1, src2[8:0]); +} + +procedure {:inline 1} $CastBv32to8(src: bv32) returns (dst: bv8) +{ + if ($Gt'Bv32'(src, 255bv32)) { + call $ExecFailureAbort(); + return; + } + dst := src[8:0]; +} + + + +function $shlBv8From32(src1: bv8, src2: bv32) returns (bv8) +{ + $Shl'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShlBv8From32(src1: bv8, src2: bv32) returns (dst: bv8) +{ + if ($Ge'Bv32'(src2, 8bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv8'(src1, src2[8:0]); +} + +function $shrBv8From32(src1: bv8, src2: bv32) returns (bv8) +{ + $Shr'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShrBv8From32(src1: bv8, src2: bv32) returns (dst: bv8) +{ + if ($Ge'Bv32'(src2, 8bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv8'(src1, src2[8:0]); +} + +procedure {:inline 1} $CastBv64to8(src: bv64) returns (dst: bv8) +{ + if ($Gt'Bv64'(src, 255bv64)) { + call $ExecFailureAbort(); + return; + } + dst := src[8:0]; +} + + +function $castBv64to8(src: bv64) returns (bv8) +{ + if ($Gt'Bv64'(src, 255bv64)) then + $Arbitrary_value_of'bv8'() + else + src[8:0] +} + + +function $shlBv8From64(src1: bv8, src2: bv64) returns (bv8) +{ + $Shl'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShlBv8From64(src1: bv8, src2: bv64) returns (dst: bv8) +{ + if ($Ge'Bv64'(src2, 8bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv8'(src1, src2[8:0]); +} + +function $shrBv8From64(src1: bv8, src2: bv64) returns (bv8) +{ + $Shr'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShrBv8From64(src1: bv8, src2: bv64) returns (dst: bv8) +{ + if ($Ge'Bv64'(src2, 8bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv8'(src1, src2[8:0]); +} + +procedure {:inline 1} $CastBv128to8(src: bv128) returns (dst: bv8) +{ + if ($Gt'Bv128'(src, 255bv128)) { + call $ExecFailureAbort(); + return; + } + dst := src[8:0]; +} + + + +function $shlBv8From128(src1: bv8, src2: bv128) returns (bv8) +{ + $Shl'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShlBv8From128(src1: bv8, src2: bv128) returns (dst: bv8) +{ + if ($Ge'Bv128'(src2, 8bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv8'(src1, src2[8:0]); +} + +function $shrBv8From128(src1: bv8, src2: bv128) returns (bv8) +{ + $Shr'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShrBv8From128(src1: bv8, src2: bv128) returns (dst: bv8) +{ + if ($Ge'Bv128'(src2, 8bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv8'(src1, src2[8:0]); +} + +procedure {:inline 1} $CastBv256to8(src: bv256) returns (dst: bv8) +{ + if ($Gt'Bv256'(src, 255bv256)) { + call $ExecFailureAbort(); + return; + } + dst := src[8:0]; +} + + +function $castBv256to8(src: bv256) returns (bv8) +{ + if ($Gt'Bv256'(src, 255bv256)) then + $Arbitrary_value_of'bv8'() + else + src[8:0] +} + + +function $shlBv8From256(src1: bv8, src2: bv256) returns (bv8) +{ + $Shl'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShlBv8From256(src1: bv8, src2: bv256) returns (dst: bv8) +{ + if ($Ge'Bv256'(src2, 8bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv8'(src1, src2[8:0]); +} + +function $shrBv8From256(src1: bv8, src2: bv256) returns (bv8) +{ + $Shr'Bv8'(src1, src2[8:0]) +} + +procedure {:inline 1} $ShrBv8From256(src1: bv8, src2: bv256) returns (dst: bv8) +{ + if ($Ge'Bv256'(src2, 8bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv8'(src1, src2[8:0]); +} + +procedure {:inline 1} $CastBv8to16(src: bv8) returns (dst: bv16) +{ + dst := 0bv8 ++ src; +} + + + +function $shlBv16From8(src1: bv16, src2: bv8) returns (bv16) +{ + $Shl'Bv16'(src1, 0bv8 ++ src2) +} + +procedure {:inline 1} $ShlBv16From8(src1: bv16, src2: bv8) returns (dst: bv16) +{ + if ($Ge'Bv8'(src2, 16bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv16'(src1, 0bv8 ++ src2); +} + +function $shrBv16From8(src1: bv16, src2: bv8) returns (bv16) +{ + $Shr'Bv16'(src1, 0bv8 ++ src2) +} + +procedure {:inline 1} $ShrBv16From8(src1: bv16, src2: bv8) returns (dst: bv16) +{ + if ($Ge'Bv8'(src2, 16bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv16'(src1, 0bv8 ++ src2); +} + +procedure {:inline 1} $CastBv16to16(src: bv16) returns (dst: bv16) +{ + dst := src; +} + + + +function $shlBv16From16(src1: bv16, src2: bv16) returns (bv16) +{ + $Shl'Bv16'(src1, src2) +} + +procedure {:inline 1} $ShlBv16From16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if ($Ge'Bv16'(src2, 16bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv16'(src1, src2); +} + +function $shrBv16From16(src1: bv16, src2: bv16) returns (bv16) +{ + $Shr'Bv16'(src1, src2) +} + +procedure {:inline 1} $ShrBv16From16(src1: bv16, src2: bv16) returns (dst: bv16) +{ + if ($Ge'Bv16'(src2, 16bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv16'(src1, src2); +} + +procedure {:inline 1} $CastBv32to16(src: bv32) returns (dst: bv16) +{ + if ($Gt'Bv32'(src, 65535bv32)) { + call $ExecFailureAbort(); + return; + } + dst := src[16:0]; +} + + + +function $shlBv16From32(src1: bv16, src2: bv32) returns (bv16) +{ + $Shl'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShlBv16From32(src1: bv16, src2: bv32) returns (dst: bv16) +{ + if ($Ge'Bv32'(src2, 16bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv16'(src1, src2[16:0]); +} + +function $shrBv16From32(src1: bv16, src2: bv32) returns (bv16) +{ + $Shr'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShrBv16From32(src1: bv16, src2: bv32) returns (dst: bv16) +{ + if ($Ge'Bv32'(src2, 16bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv16'(src1, src2[16:0]); +} + +procedure {:inline 1} $CastBv64to16(src: bv64) returns (dst: bv16) +{ + if ($Gt'Bv64'(src, 65535bv64)) { + call $ExecFailureAbort(); + return; + } + dst := src[16:0]; +} + + + +function $shlBv16From64(src1: bv16, src2: bv64) returns (bv16) +{ + $Shl'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShlBv16From64(src1: bv16, src2: bv64) returns (dst: bv16) +{ + if ($Ge'Bv64'(src2, 16bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv16'(src1, src2[16:0]); +} + +function $shrBv16From64(src1: bv16, src2: bv64) returns (bv16) +{ + $Shr'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShrBv16From64(src1: bv16, src2: bv64) returns (dst: bv16) +{ + if ($Ge'Bv64'(src2, 16bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv16'(src1, src2[16:0]); +} + +procedure {:inline 1} $CastBv128to16(src: bv128) returns (dst: bv16) +{ + if ($Gt'Bv128'(src, 65535bv128)) { + call $ExecFailureAbort(); + return; + } + dst := src[16:0]; +} + + + +function $shlBv16From128(src1: bv16, src2: bv128) returns (bv16) +{ + $Shl'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShlBv16From128(src1: bv16, src2: bv128) returns (dst: bv16) +{ + if ($Ge'Bv128'(src2, 16bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv16'(src1, src2[16:0]); +} + +function $shrBv16From128(src1: bv16, src2: bv128) returns (bv16) +{ + $Shr'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShrBv16From128(src1: bv16, src2: bv128) returns (dst: bv16) +{ + if ($Ge'Bv128'(src2, 16bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv16'(src1, src2[16:0]); +} + +procedure {:inline 1} $CastBv256to16(src: bv256) returns (dst: bv16) +{ + if ($Gt'Bv256'(src, 65535bv256)) { + call $ExecFailureAbort(); + return; + } + dst := src[16:0]; +} + + + +function $shlBv16From256(src1: bv16, src2: bv256) returns (bv16) +{ + $Shl'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShlBv16From256(src1: bv16, src2: bv256) returns (dst: bv16) +{ + if ($Ge'Bv256'(src2, 16bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv16'(src1, src2[16:0]); +} + +function $shrBv16From256(src1: bv16, src2: bv256) returns (bv16) +{ + $Shr'Bv16'(src1, src2[16:0]) +} + +procedure {:inline 1} $ShrBv16From256(src1: bv16, src2: bv256) returns (dst: bv16) +{ + if ($Ge'Bv256'(src2, 16bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv16'(src1, src2[16:0]); +} + +procedure {:inline 1} $CastBv8to32(src: bv8) returns (dst: bv32) +{ + dst := 0bv24 ++ src; +} + + + +function $shlBv32From8(src1: bv32, src2: bv8) returns (bv32) +{ + $Shl'Bv32'(src1, 0bv24 ++ src2) +} + +procedure {:inline 1} $ShlBv32From8(src1: bv32, src2: bv8) returns (dst: bv32) +{ + if ($Ge'Bv8'(src2, 32bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv32'(src1, 0bv24 ++ src2); +} + +function $shrBv32From8(src1: bv32, src2: bv8) returns (bv32) +{ + $Shr'Bv32'(src1, 0bv24 ++ src2) +} + +procedure {:inline 1} $ShrBv32From8(src1: bv32, src2: bv8) returns (dst: bv32) +{ + if ($Ge'Bv8'(src2, 32bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv32'(src1, 0bv24 ++ src2); +} + +procedure {:inline 1} $CastBv16to32(src: bv16) returns (dst: bv32) +{ + dst := 0bv16 ++ src; +} + + + +function $shlBv32From16(src1: bv32, src2: bv16) returns (bv32) +{ + $Shl'Bv32'(src1, 0bv16 ++ src2) +} + +procedure {:inline 1} $ShlBv32From16(src1: bv32, src2: bv16) returns (dst: bv32) +{ + if ($Ge'Bv16'(src2, 32bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv32'(src1, 0bv16 ++ src2); +} + +function $shrBv32From16(src1: bv32, src2: bv16) returns (bv32) +{ + $Shr'Bv32'(src1, 0bv16 ++ src2) +} + +procedure {:inline 1} $ShrBv32From16(src1: bv32, src2: bv16) returns (dst: bv32) +{ + if ($Ge'Bv16'(src2, 32bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv32'(src1, 0bv16 ++ src2); +} + +procedure {:inline 1} $CastBv32to32(src: bv32) returns (dst: bv32) +{ + dst := src; +} + + + +function $shlBv32From32(src1: bv32, src2: bv32) returns (bv32) +{ + $Shl'Bv32'(src1, src2) +} + +procedure {:inline 1} $ShlBv32From32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if ($Ge'Bv32'(src2, 32bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv32'(src1, src2); +} + +function $shrBv32From32(src1: bv32, src2: bv32) returns (bv32) +{ + $Shr'Bv32'(src1, src2) +} + +procedure {:inline 1} $ShrBv32From32(src1: bv32, src2: bv32) returns (dst: bv32) +{ + if ($Ge'Bv32'(src2, 32bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv32'(src1, src2); +} + +procedure {:inline 1} $CastBv64to32(src: bv64) returns (dst: bv32) +{ + if ($Gt'Bv64'(src, 2147483647bv64)) { + call $ExecFailureAbort(); + return; + } + dst := src[32:0]; +} + + + +function $shlBv32From64(src1: bv32, src2: bv64) returns (bv32) +{ + $Shl'Bv32'(src1, src2[32:0]) +} + +procedure {:inline 1} $ShlBv32From64(src1: bv32, src2: bv64) returns (dst: bv32) +{ + if ($Ge'Bv64'(src2, 32bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv32'(src1, src2[32:0]); +} + +function $shrBv32From64(src1: bv32, src2: bv64) returns (bv32) +{ + $Shr'Bv32'(src1, src2[32:0]) +} + +procedure {:inline 1} $ShrBv32From64(src1: bv32, src2: bv64) returns (dst: bv32) +{ + if ($Ge'Bv64'(src2, 32bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv32'(src1, src2[32:0]); +} + +procedure {:inline 1} $CastBv128to32(src: bv128) returns (dst: bv32) +{ + if ($Gt'Bv128'(src, 2147483647bv128)) { + call $ExecFailureAbort(); + return; + } + dst := src[32:0]; +} + + + +function $shlBv32From128(src1: bv32, src2: bv128) returns (bv32) +{ + $Shl'Bv32'(src1, src2[32:0]) +} + +procedure {:inline 1} $ShlBv32From128(src1: bv32, src2: bv128) returns (dst: bv32) +{ + if ($Ge'Bv128'(src2, 32bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv32'(src1, src2[32:0]); +} + +function $shrBv32From128(src1: bv32, src2: bv128) returns (bv32) +{ + $Shr'Bv32'(src1, src2[32:0]) +} + +procedure {:inline 1} $ShrBv32From128(src1: bv32, src2: bv128) returns (dst: bv32) +{ + if ($Ge'Bv128'(src2, 32bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv32'(src1, src2[32:0]); +} + +procedure {:inline 1} $CastBv256to32(src: bv256) returns (dst: bv32) +{ + if ($Gt'Bv256'(src, 2147483647bv256)) { + call $ExecFailureAbort(); + return; + } + dst := src[32:0]; +} + + + +function $shlBv32From256(src1: bv32, src2: bv256) returns (bv32) +{ + $Shl'Bv32'(src1, src2[32:0]) +} + +procedure {:inline 1} $ShlBv32From256(src1: bv32, src2: bv256) returns (dst: bv32) +{ + if ($Ge'Bv256'(src2, 32bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv32'(src1, src2[32:0]); +} + +function $shrBv32From256(src1: bv32, src2: bv256) returns (bv32) +{ + $Shr'Bv32'(src1, src2[32:0]) +} + +procedure {:inline 1} $ShrBv32From256(src1: bv32, src2: bv256) returns (dst: bv32) +{ + if ($Ge'Bv256'(src2, 32bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv32'(src1, src2[32:0]); +} + +procedure {:inline 1} $CastBv8to64(src: bv8) returns (dst: bv64) +{ + dst := 0bv56 ++ src; +} + + +function $castBv8to64(src: bv8) returns (bv64) +{ + 0bv56 ++ src +} + + +function $shlBv64From8(src1: bv64, src2: bv8) returns (bv64) +{ + $Shl'Bv64'(src1, 0bv56 ++ src2) +} + +procedure {:inline 1} $ShlBv64From8(src1: bv64, src2: bv8) returns (dst: bv64) +{ + if ($Ge'Bv8'(src2, 64bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv64'(src1, 0bv56 ++ src2); +} + +function $shrBv64From8(src1: bv64, src2: bv8) returns (bv64) +{ + $Shr'Bv64'(src1, 0bv56 ++ src2) +} + +procedure {:inline 1} $ShrBv64From8(src1: bv64, src2: bv8) returns (dst: bv64) +{ + if ($Ge'Bv8'(src2, 64bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv64'(src1, 0bv56 ++ src2); +} + +procedure {:inline 1} $CastBv16to64(src: bv16) returns (dst: bv64) +{ + dst := 0bv48 ++ src; +} + + + +function $shlBv64From16(src1: bv64, src2: bv16) returns (bv64) +{ + $Shl'Bv64'(src1, 0bv48 ++ src2) +} + +procedure {:inline 1} $ShlBv64From16(src1: bv64, src2: bv16) returns (dst: bv64) +{ + if ($Ge'Bv16'(src2, 64bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv64'(src1, 0bv48 ++ src2); +} + +function $shrBv64From16(src1: bv64, src2: bv16) returns (bv64) +{ + $Shr'Bv64'(src1, 0bv48 ++ src2) +} + +procedure {:inline 1} $ShrBv64From16(src1: bv64, src2: bv16) returns (dst: bv64) +{ + if ($Ge'Bv16'(src2, 64bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv64'(src1, 0bv48 ++ src2); +} + +procedure {:inline 1} $CastBv32to64(src: bv32) returns (dst: bv64) +{ + dst := 0bv32 ++ src; +} + + + +function $shlBv64From32(src1: bv64, src2: bv32) returns (bv64) +{ + $Shl'Bv64'(src1, 0bv32 ++ src2) +} + +procedure {:inline 1} $ShlBv64From32(src1: bv64, src2: bv32) returns (dst: bv64) +{ + if ($Ge'Bv32'(src2, 64bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv64'(src1, 0bv32 ++ src2); +} + +function $shrBv64From32(src1: bv64, src2: bv32) returns (bv64) +{ + $Shr'Bv64'(src1, 0bv32 ++ src2) +} + +procedure {:inline 1} $ShrBv64From32(src1: bv64, src2: bv32) returns (dst: bv64) +{ + if ($Ge'Bv32'(src2, 64bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv64'(src1, 0bv32 ++ src2); +} + +procedure {:inline 1} $CastBv64to64(src: bv64) returns (dst: bv64) +{ + dst := src; +} + + +function $castBv64to64(src: bv64) returns (bv64) +{ + src +} + + +function $shlBv64From64(src1: bv64, src2: bv64) returns (bv64) +{ + $Shl'Bv64'(src1, src2) +} + +procedure {:inline 1} $ShlBv64From64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if ($Ge'Bv64'(src2, 64bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv64'(src1, src2); +} + +function $shrBv64From64(src1: bv64, src2: bv64) returns (bv64) +{ + $Shr'Bv64'(src1, src2) +} + +procedure {:inline 1} $ShrBv64From64(src1: bv64, src2: bv64) returns (dst: bv64) +{ + if ($Ge'Bv64'(src2, 64bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv64'(src1, src2); +} + +procedure {:inline 1} $CastBv128to64(src: bv128) returns (dst: bv64) +{ + if ($Gt'Bv128'(src, 18446744073709551615bv128)) { + call $ExecFailureAbort(); + return; + } + dst := src[64:0]; +} + + + +function $shlBv64From128(src1: bv64, src2: bv128) returns (bv64) +{ + $Shl'Bv64'(src1, src2[64:0]) +} + +procedure {:inline 1} $ShlBv64From128(src1: bv64, src2: bv128) returns (dst: bv64) +{ + if ($Ge'Bv128'(src2, 64bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv64'(src1, src2[64:0]); +} + +function $shrBv64From128(src1: bv64, src2: bv128) returns (bv64) +{ + $Shr'Bv64'(src1, src2[64:0]) +} + +procedure {:inline 1} $ShrBv64From128(src1: bv64, src2: bv128) returns (dst: bv64) +{ + if ($Ge'Bv128'(src2, 64bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv64'(src1, src2[64:0]); +} + +procedure {:inline 1} $CastBv256to64(src: bv256) returns (dst: bv64) +{ + if ($Gt'Bv256'(src, 18446744073709551615bv256)) { + call $ExecFailureAbort(); + return; + } + dst := src[64:0]; +} + + +function $castBv256to64(src: bv256) returns (bv64) +{ + if ($Gt'Bv256'(src, 18446744073709551615bv256)) then + $Arbitrary_value_of'bv64'() + else + src[64:0] +} + + +function $shlBv64From256(src1: bv64, src2: bv256) returns (bv64) +{ + $Shl'Bv64'(src1, src2[64:0]) +} + +procedure {:inline 1} $ShlBv64From256(src1: bv64, src2: bv256) returns (dst: bv64) +{ + if ($Ge'Bv256'(src2, 64bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv64'(src1, src2[64:0]); +} + +function $shrBv64From256(src1: bv64, src2: bv256) returns (bv64) +{ + $Shr'Bv64'(src1, src2[64:0]) +} + +procedure {:inline 1} $ShrBv64From256(src1: bv64, src2: bv256) returns (dst: bv64) +{ + if ($Ge'Bv256'(src2, 64bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv64'(src1, src2[64:0]); +} + +procedure {:inline 1} $CastBv8to128(src: bv8) returns (dst: bv128) +{ + dst := 0bv120 ++ src; +} + + + +function $shlBv128From8(src1: bv128, src2: bv8) returns (bv128) +{ + $Shl'Bv128'(src1, 0bv120 ++ src2) +} + +procedure {:inline 1} $ShlBv128From8(src1: bv128, src2: bv8) returns (dst: bv128) +{ + if ($Ge'Bv8'(src2, 128bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv128'(src1, 0bv120 ++ src2); +} + +function $shrBv128From8(src1: bv128, src2: bv8) returns (bv128) +{ + $Shr'Bv128'(src1, 0bv120 ++ src2) +} + +procedure {:inline 1} $ShrBv128From8(src1: bv128, src2: bv8) returns (dst: bv128) +{ + if ($Ge'Bv8'(src2, 128bv8)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv128'(src1, 0bv120 ++ src2); +} + +procedure {:inline 1} $CastBv16to128(src: bv16) returns (dst: bv128) +{ + dst := 0bv112 ++ src; +} + + + +function $shlBv128From16(src1: bv128, src2: bv16) returns (bv128) +{ + $Shl'Bv128'(src1, 0bv112 ++ src2) +} + +procedure {:inline 1} $ShlBv128From16(src1: bv128, src2: bv16) returns (dst: bv128) +{ + if ($Ge'Bv16'(src2, 128bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv128'(src1, 0bv112 ++ src2); +} + +function $shrBv128From16(src1: bv128, src2: bv16) returns (bv128) +{ + $Shr'Bv128'(src1, 0bv112 ++ src2) +} + +procedure {:inline 1} $ShrBv128From16(src1: bv128, src2: bv16) returns (dst: bv128) +{ + if ($Ge'Bv16'(src2, 128bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv128'(src1, 0bv112 ++ src2); +} + +procedure {:inline 1} $CastBv32to128(src: bv32) returns (dst: bv128) +{ + dst := 0bv96 ++ src; +} + + + +function $shlBv128From32(src1: bv128, src2: bv32) returns (bv128) +{ + $Shl'Bv128'(src1, 0bv96 ++ src2) +} + +procedure {:inline 1} $ShlBv128From32(src1: bv128, src2: bv32) returns (dst: bv128) +{ + if ($Ge'Bv32'(src2, 128bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv128'(src1, 0bv96 ++ src2); +} + +function $shrBv128From32(src1: bv128, src2: bv32) returns (bv128) +{ + $Shr'Bv128'(src1, 0bv96 ++ src2) +} + +procedure {:inline 1} $ShrBv128From32(src1: bv128, src2: bv32) returns (dst: bv128) +{ + if ($Ge'Bv32'(src2, 128bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv128'(src1, 0bv96 ++ src2); +} + +procedure {:inline 1} $CastBv64to128(src: bv64) returns (dst: bv128) +{ + dst := 0bv64 ++ src; +} + + + +function $shlBv128From64(src1: bv128, src2: bv64) returns (bv128) +{ + $Shl'Bv128'(src1, 0bv64 ++ src2) +} + +procedure {:inline 1} $ShlBv128From64(src1: bv128, src2: bv64) returns (dst: bv128) +{ + if ($Ge'Bv64'(src2, 128bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv128'(src1, 0bv64 ++ src2); +} + +function $shrBv128From64(src1: bv128, src2: bv64) returns (bv128) +{ + $Shr'Bv128'(src1, 0bv64 ++ src2) +} + +procedure {:inline 1} $ShrBv128From64(src1: bv128, src2: bv64) returns (dst: bv128) +{ + if ($Ge'Bv64'(src2, 128bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv128'(src1, 0bv64 ++ src2); +} + +procedure {:inline 1} $CastBv128to128(src: bv128) returns (dst: bv128) +{ + dst := src; +} + + + +function $shlBv128From128(src1: bv128, src2: bv128) returns (bv128) +{ + $Shl'Bv128'(src1, src2) +} + +procedure {:inline 1} $ShlBv128From128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if ($Ge'Bv128'(src2, 128bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv128'(src1, src2); +} + +function $shrBv128From128(src1: bv128, src2: bv128) returns (bv128) +{ + $Shr'Bv128'(src1, src2) +} + +procedure {:inline 1} $ShrBv128From128(src1: bv128, src2: bv128) returns (dst: bv128) +{ + if ($Ge'Bv128'(src2, 128bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv128'(src1, src2); +} + +procedure {:inline 1} $CastBv256to128(src: bv256) returns (dst: bv128) +{ + if ($Gt'Bv256'(src, 340282366920938463463374607431768211455bv256)) { + call $ExecFailureAbort(); + return; + } + dst := src[128:0]; +} + + + +function $shlBv128From256(src1: bv128, src2: bv256) returns (bv128) +{ + $Shl'Bv128'(src1, src2[128:0]) +} + +procedure {:inline 1} $ShlBv128From256(src1: bv128, src2: bv256) returns (dst: bv128) +{ + if ($Ge'Bv256'(src2, 128bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv128'(src1, src2[128:0]); +} + +function $shrBv128From256(src1: bv128, src2: bv256) returns (bv128) +{ + $Shr'Bv128'(src1, src2[128:0]) +} + +procedure {:inline 1} $ShrBv128From256(src1: bv128, src2: bv256) returns (dst: bv128) +{ + if ($Ge'Bv256'(src2, 128bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv128'(src1, src2[128:0]); +} + +procedure {:inline 1} $CastBv8to256(src: bv8) returns (dst: bv256) +{ + dst := 0bv248 ++ src; +} + + +function $castBv8to256(src: bv8) returns (bv256) +{ + 0bv248 ++ src +} + + +function $shlBv256From8(src1: bv256, src2: bv8) returns (bv256) +{ + $Shl'Bv256'(src1, 0bv248 ++ src2) +} + +procedure {:inline 1} $ShlBv256From8(src1: bv256, src2: bv8) returns (dst: bv256) +{ + assume $bv2int.8(src2) >= 0 && $bv2int.8(src2) < 256; + dst := $Shl'Bv256'(src1, 0bv248 ++ src2); +} + +function $shrBv256From8(src1: bv256, src2: bv8) returns (bv256) +{ + $Shr'Bv256'(src1, 0bv248 ++ src2) +} + +procedure {:inline 1} $ShrBv256From8(src1: bv256, src2: bv8) returns (dst: bv256) +{ + assume $bv2int.8(src2) >= 0 && $bv2int.8(src2) < 256; + dst := $Shr'Bv256'(src1, 0bv248 ++ src2); +} + +procedure {:inline 1} $CastBv16to256(src: bv16) returns (dst: bv256) +{ + dst := 0bv240 ++ src; +} + + + +function $shlBv256From16(src1: bv256, src2: bv16) returns (bv256) +{ + $Shl'Bv256'(src1, 0bv240 ++ src2) +} + +procedure {:inline 1} $ShlBv256From16(src1: bv256, src2: bv16) returns (dst: bv256) +{ + if ($Ge'Bv16'(src2, 256bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv256'(src1, 0bv240 ++ src2); +} + +function $shrBv256From16(src1: bv256, src2: bv16) returns (bv256) +{ + $Shr'Bv256'(src1, 0bv240 ++ src2) +} + +procedure {:inline 1} $ShrBv256From16(src1: bv256, src2: bv16) returns (dst: bv256) +{ + if ($Ge'Bv16'(src2, 256bv16)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv256'(src1, 0bv240 ++ src2); +} + +procedure {:inline 1} $CastBv32to256(src: bv32) returns (dst: bv256) +{ + dst := 0bv224 ++ src; +} + + + +function $shlBv256From32(src1: bv256, src2: bv32) returns (bv256) +{ + $Shl'Bv256'(src1, 0bv224 ++ src2) +} + +procedure {:inline 1} $ShlBv256From32(src1: bv256, src2: bv32) returns (dst: bv256) +{ + if ($Ge'Bv32'(src2, 256bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv256'(src1, 0bv224 ++ src2); +} + +function $shrBv256From32(src1: bv256, src2: bv32) returns (bv256) +{ + $Shr'Bv256'(src1, 0bv224 ++ src2) +} + +procedure {:inline 1} $ShrBv256From32(src1: bv256, src2: bv32) returns (dst: bv256) +{ + if ($Ge'Bv32'(src2, 256bv32)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv256'(src1, 0bv224 ++ src2); +} + +procedure {:inline 1} $CastBv64to256(src: bv64) returns (dst: bv256) +{ + dst := 0bv192 ++ src; +} + + +function $castBv64to256(src: bv64) returns (bv256) +{ + 0bv192 ++ src +} + + +function $shlBv256From64(src1: bv256, src2: bv64) returns (bv256) +{ + $Shl'Bv256'(src1, 0bv192 ++ src2) +} + +procedure {:inline 1} $ShlBv256From64(src1: bv256, src2: bv64) returns (dst: bv256) +{ + if ($Ge'Bv64'(src2, 256bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv256'(src1, 0bv192 ++ src2); +} + +function $shrBv256From64(src1: bv256, src2: bv64) returns (bv256) +{ + $Shr'Bv256'(src1, 0bv192 ++ src2) +} + +procedure {:inline 1} $ShrBv256From64(src1: bv256, src2: bv64) returns (dst: bv256) +{ + if ($Ge'Bv64'(src2, 256bv64)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv256'(src1, 0bv192 ++ src2); +} + +procedure {:inline 1} $CastBv128to256(src: bv128) returns (dst: bv256) +{ + dst := 0bv128 ++ src; +} + + + +function $shlBv256From128(src1: bv256, src2: bv128) returns (bv256) +{ + $Shl'Bv256'(src1, 0bv128 ++ src2) +} + +procedure {:inline 1} $ShlBv256From128(src1: bv256, src2: bv128) returns (dst: bv256) +{ + if ($Ge'Bv128'(src2, 256bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv256'(src1, 0bv128 ++ src2); +} + +function $shrBv256From128(src1: bv256, src2: bv128) returns (bv256) +{ + $Shr'Bv256'(src1, 0bv128 ++ src2) +} + +procedure {:inline 1} $ShrBv256From128(src1: bv256, src2: bv128) returns (dst: bv256) +{ + if ($Ge'Bv128'(src2, 256bv128)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv256'(src1, 0bv128 ++ src2); +} + +procedure {:inline 1} $CastBv256to256(src: bv256) returns (dst: bv256) +{ + dst := src; +} + + +function $castBv256to256(src: bv256) returns (bv256) +{ + src +} + + +function $shlBv256From256(src1: bv256, src2: bv256) returns (bv256) +{ + $Shl'Bv256'(src1, src2) +} + +procedure {:inline 1} $ShlBv256From256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if ($Ge'Bv256'(src2, 256bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shl'Bv256'(src1, src2); +} + +function $shrBv256From256(src1: bv256, src2: bv256) returns (bv256) +{ + $Shr'Bv256'(src1, src2) +} + +procedure {:inline 1} $ShrBv256From256(src1: bv256, src2: bv256) returns (dst: bv256) +{ + if ($Ge'Bv256'(src2, 256bv256)) { + call $ExecFailureAbort(); + return; + } + + dst := $Shr'Bv256'(src1, src2); +} + +procedure {:inline 1} $ShlU16(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 16) { + call $ExecFailureAbort(); + return; + } + dst := $shlU16(src1, src2); +} + +procedure {:inline 1} $ShlU32(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 32) { + call $ExecFailureAbort(); + return; + } + dst := $shlU32(src1, src2); +} + +procedure {:inline 1} $ShlU64(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 64) { + call $ExecFailureAbort(); + return; + } + dst := $shlU64(src1, src2); +} + +procedure {:inline 1} $ShlU128(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 128) { + call $ExecFailureAbort(); + return; + } + dst := $shlU128(src1, src2); +} + +procedure {:inline 1} $ShlU256(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + dst := $shlU256(src1, src2); +} + +procedure {:inline 1} $Shr(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + dst := $shr(src1, src2); +} + +procedure {:inline 1} $ShrU8(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 8) { + call $ExecFailureAbort(); + return; + } + dst := $shr(src1, src2); +} + +procedure {:inline 1} $ShrU16(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 16) { + call $ExecFailureAbort(); + return; + } + dst := $shr(src1, src2); +} + +procedure {:inline 1} $ShrU32(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 32) { + call $ExecFailureAbort(); + return; + } + dst := $shr(src1, src2); +} + +procedure {:inline 1} $ShrU64(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 64) { + call $ExecFailureAbort(); + return; + } + dst := $shr(src1, src2); +} + +procedure {:inline 1} $ShrU128(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + if (src2 >= 128) { + call $ExecFailureAbort(); + return; + } + dst := $shr(src1, src2); +} + +procedure {:inline 1} $ShrU256(src1: int, src2: int) returns (dst: int) +{ + var res: int; + // src2 is a u8 + assume src2 >= 0 && src2 < 256; + dst := $shr(src1, src2); +} + +procedure {:inline 1} $MulU8(src1: int, src2: int) returns (dst: int) +{ + if (src1 * src2 > $MAX_U8) { + call $ExecFailureAbort(); + return; + } + dst := src1 * src2; +} + +procedure {:inline 1} $MulU16(src1: int, src2: int) returns (dst: int) +{ + if (src1 * src2 > $MAX_U16) { + call $ExecFailureAbort(); + return; + } + dst := src1 * src2; +} + +procedure {:inline 1} $MulU32(src1: int, src2: int) returns (dst: int) +{ + if (src1 * src2 > $MAX_U32) { + call $ExecFailureAbort(); + return; + } + dst := src1 * src2; +} + +procedure {:inline 1} $MulU64(src1: int, src2: int) returns (dst: int) +{ + if (src1 * src2 > $MAX_U64) { + call $ExecFailureAbort(); + return; + } + dst := src1 * src2; +} + +procedure {:inline 1} $MulU128(src1: int, src2: int) returns (dst: int) +{ + if (src1 * src2 > $MAX_U128) { + call $ExecFailureAbort(); + return; + } + dst := src1 * src2; +} + +procedure {:inline 1} $MulU256(src1: int, src2: int) returns (dst: int) +{ + if (src1 * src2 > $MAX_U256) { + call $ExecFailureAbort(); + return; + } + dst := src1 * src2; +} + +procedure {:inline 1} $Div(src1: int, src2: int) returns (dst: int) +{ + if (src2 == 0) { + call $ExecFailureAbort(); + return; + } + dst := src1 div src2; +} + +procedure {:inline 1} $Mod(src1: int, src2: int) returns (dst: int) +{ + if (src2 == 0) { + call $ExecFailureAbort(); + return; + } + dst := src1 mod src2; +} + +procedure {:inline 1} $ArithBinaryUnimplemented(src1: int, src2: int) returns (dst: int); + +procedure {:inline 1} $Lt(src1: int, src2: int) returns (dst: bool) +{ + dst := src1 < src2; +} + +procedure {:inline 1} $Gt(src1: int, src2: int) returns (dst: bool) +{ + dst := src1 > src2; +} + +procedure {:inline 1} $Le(src1: int, src2: int) returns (dst: bool) +{ + dst := src1 <= src2; +} + +procedure {:inline 1} $Ge(src1: int, src2: int) returns (dst: bool) +{ + dst := src1 >= src2; +} + +procedure {:inline 1} $And(src1: bool, src2: bool) returns (dst: bool) +{ + dst := src1 && src2; +} + +procedure {:inline 1} $Or(src1: bool, src2: bool) returns (dst: bool) +{ + dst := src1 || src2; +} + +procedure {:inline 1} $Not(src: bool) returns (dst: bool) +{ + dst := !src; +} + +// Pack and Unpack are auto-generated for each type T + + +// ================================================================================== +// Native Vector + +function {:inline} $SliceVecByRange(v: Vec T, r: $Range): Vec T { + SliceVec(v, r->lb, r->ub) +} + +// ---------------------------------------------------------------------------------- +// Native Vector implementation for element type `#0` + +// Not inlined. It appears faster this way. +function $IsEqual'vec'#0''(v1: Vec (#0), v2: Vec (#0)): bool { + LenVec(v1) == LenVec(v2) && + (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'#0'(ReadVec(v1, i), ReadVec(v2, i))) +} + +// Not inlined. +function $IsPrefix'vec'#0''(v: Vec (#0), prefix: Vec (#0)): bool { + LenVec(v) >= LenVec(prefix) && + (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'#0'(ReadVec(v, i), ReadVec(prefix, i))) +} + +// Not inlined. +function $IsSuffix'vec'#0''(v: Vec (#0), suffix: Vec (#0)): bool { + LenVec(v) >= LenVec(suffix) && + (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'#0'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) +} + +// Not inlined. +function $IsValid'vec'#0''(v: Vec (#0)): bool { + $IsValid'u64'(LenVec(v)) && + (forall i: int:: InRangeVec(v, i) ==> $IsValid'#0'(ReadVec(v, i))) +} + + +function {:inline} $ContainsVec'#0'(v: Vec (#0), e: #0): bool { + (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'#0'(ReadVec(v, i), e)) +} + +function $IndexOfVec'#0'(v: Vec (#0), e: #0): int; +axiom (forall v: Vec (#0), e: #0:: {$IndexOfVec'#0'(v, e)} + (var i := $IndexOfVec'#0'(v, e); + if (!$ContainsVec'#0'(v, e)) then i == -1 + else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'#0'(ReadVec(v, i), e) && + (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'#0'(ReadVec(v, j), e)))); + + +function {:inline} $RangeVec'#0'(v: Vec (#0)): $Range { + $Range(0, LenVec(v)) +} + + +function {:inline} $EmptyVec'#0'(): Vec (#0) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_empty'#0'() returns (v: Vec (#0)) { + v := EmptyVec(); +} + +function {:inline} $1_vector_$empty'#0'(): Vec (#0) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_is_empty'#0'(v: Vec (#0)) returns (b: bool) { + b := IsEmptyVec(v); +} + +procedure {:inline 1} $1_vector_push_back'#0'(m: $Mutation (Vec (#0)), val: #0) returns (m': $Mutation (Vec (#0))) { + m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); +} + +function {:inline} $1_vector_$push_back'#0'(v: Vec (#0), val: #0): Vec (#0) { + ExtendVec(v, val) +} + +procedure {:inline 1} $1_vector_pop_back'#0'(m: $Mutation (Vec (#0))) returns (e: #0, m': $Mutation (Vec (#0))) { + var v: Vec (#0); + var len: int; + v := $Dereference(m); + len := LenVec(v); + if (len == 0) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, len-1); + m' := $UpdateMutation(m, RemoveVec(v)); +} + +procedure {:inline 1} $1_vector_append'#0'(m: $Mutation (Vec (#0)), other: Vec (#0)) returns (m': $Mutation (Vec (#0))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); +} + +procedure {:inline 1} $1_vector_reverse'#0'(m: $Mutation (Vec (#0))) returns (m': $Mutation (Vec (#0))) { + m' := $UpdateMutation(m, ReverseVec($Dereference(m))); +} + +procedure {:inline 1} $1_vector_reverse_append'#0'(m: $Mutation (Vec (#0)), other: Vec (#0)) returns (m': $Mutation (Vec (#0))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); +} + +procedure {:inline 1} $1_vector_trim_reverse'#0'(m: $Mutation (Vec (#0)), new_len: int) returns (v: (Vec (#0)), m': $Mutation (Vec (#0))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + v := ReverseVec(v); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_trim'#0'(m: $Mutation (Vec (#0)), new_len: int) returns (v: (Vec (#0)), m': $Mutation (Vec (#0))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_reverse_slice'#0'(m: $Mutation (Vec (#0)), left: int, right: int) returns (m': $Mutation (Vec (#0))) { + var left_vec: Vec (#0); + var mid_vec: Vec (#0); + var right_vec: Vec (#0); + var v: Vec (#0); + if (left > right) { + call $ExecFailureAbort(); + return; + } + if (left == right) { + m' := m; + return; + } + v := $Dereference(m); + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_vec := ReverseVec(SliceVec(v, left, right)); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); +} + +procedure {:inline 1} $1_vector_rotate'#0'(m: $Mutation (Vec (#0)), rot: int) returns (n: int, m': $Mutation (Vec (#0))) { + var v: Vec (#0); + var len: int; + var left_vec: Vec (#0); + var right_vec: Vec (#0); + v := $Dereference(m); + if (!(rot >= 0 && rot <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, rot); + right_vec := SliceVec(v, rot, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); + n := LenVec(v) - rot; +} + +procedure {:inline 1} $1_vector_rotate_slice'#0'(m: $Mutation (Vec (#0)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (#0))) { + var left_vec: Vec (#0); + var mid_vec: Vec (#0); + var right_vec: Vec (#0); + var mid_left_vec: Vec (#0); + var mid_right_vec: Vec (#0); + var v: Vec (#0); + v := $Dereference(m); + if (!(left <= rot && rot <= right)) { + call $ExecFailureAbort(); + return; + } + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + v := $Dereference(m); + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_left_vec := SliceVec(v, left, rot); + mid_right_vec := SliceVec(v, rot, right); + mid_vec := ConcatVec(mid_right_vec, mid_left_vec); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); + n := left + (right - rot); +} + +procedure {:inline 1} $1_vector_insert'#0'(m: $Mutation (Vec (#0)), i: int, e: #0) returns (m': $Mutation (Vec (#0))) { + var left_vec: Vec (#0); + var right_vec: Vec (#0); + var v: Vec (#0); + v := $Dereference(m); + if (!(i >= 0 && i <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + if (i == LenVec(v)) { + m' := $UpdateMutation(m, ExtendVec(v, e)); + } else { + left_vec := ExtendVec(SliceVec(v, 0, i), e); + right_vec := SliceVec(v, i, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); + } +} + +procedure {:inline 1} $1_vector_length'#0'(v: Vec (#0)) returns (l: int) { + l := LenVec(v); +} + +function {:inline} $1_vector_$length'#0'(v: Vec (#0)): int { + LenVec(v) +} + +procedure {:inline 1} $1_vector_borrow'#0'(v: Vec (#0), i: int) returns (dst: #0) { + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + dst := ReadVec(v, i); +} + +function {:inline} $1_vector_$borrow'#0'(v: Vec (#0), i: int): #0 { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_borrow_mut'#0'(m: $Mutation (Vec (#0)), index: int) +returns (dst: $Mutation (#0), m': $Mutation (Vec (#0))) +{ + var v: Vec (#0); + v := $Dereference(m); + if (!InRangeVec(v, index)) { + call $ExecFailureAbort(); + return; + } + dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); + m' := m; +} + +function {:inline} $1_vector_$borrow_mut'#0'(v: Vec (#0), i: int): #0 { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_destroy_empty'#0'(v: Vec (#0)) { + if (!IsEmptyVec(v)) { + call $ExecFailureAbort(); + } +} + +procedure {:inline 1} $1_vector_swap'#0'(m: $Mutation (Vec (#0)), i: int, j: int) returns (m': $Mutation (Vec (#0))) +{ + var v: Vec (#0); + v := $Dereference(m); + if (!InRangeVec(v, i) || !InRangeVec(v, j)) { + call $ExecFailureAbort(); + return; + } + m' := $UpdateMutation(m, SwapVec(v, i, j)); +} + +function {:inline} $1_vector_$swap'#0'(v: Vec (#0), i: int, j: int): Vec (#0) { + SwapVec(v, i, j) +} + +procedure {:inline 1} $1_vector_remove'#0'(m: $Mutation (Vec (#0)), i: int) returns (e: #0, m': $Mutation (Vec (#0))) +{ + var v: Vec (#0); + + v := $Dereference(m); + + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveAtVec(v, i)); +} + +procedure {:inline 1} $1_vector_swap_remove'#0'(m: $Mutation (Vec (#0)), i: int) returns (e: #0, m': $Mutation (Vec (#0))) +{ + var len: int; + var v: Vec (#0); + + v := $Dereference(m); + len := LenVec(v); + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); +} + +procedure {:inline 1} $1_vector_contains'#0'(v: Vec (#0), e: #0) returns (res: bool) { + res := $ContainsVec'#0'(v, e); +} + +procedure {:inline 1} +$1_vector_index_of'#0'(v: Vec (#0), e: #0) returns (res1: bool, res2: int) { + res2 := $IndexOfVec'#0'(v, e); + if (res2 >= 0) { + res1 := true; + } else { + res1 := false; + res2 := 0; + } +} + + +// ---------------------------------------------------------------------------------- +// Native Vector implementation for element type `address` + +// Not inlined. It appears faster this way. +function $IsEqual'vec'address''(v1: Vec (int), v2: Vec (int)): bool { + LenVec(v1) == LenVec(v2) && + (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'address'(ReadVec(v1, i), ReadVec(v2, i))) +} + +// Not inlined. +function $IsPrefix'vec'address''(v: Vec (int), prefix: Vec (int)): bool { + LenVec(v) >= LenVec(prefix) && + (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'address'(ReadVec(v, i), ReadVec(prefix, i))) +} + +// Not inlined. +function $IsSuffix'vec'address''(v: Vec (int), suffix: Vec (int)): bool { + LenVec(v) >= LenVec(suffix) && + (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'address'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) +} + +// Not inlined. +function $IsValid'vec'address''(v: Vec (int)): bool { + $IsValid'u64'(LenVec(v)) && + (forall i: int:: InRangeVec(v, i) ==> $IsValid'address'(ReadVec(v, i))) +} + + +function {:inline} $ContainsVec'address'(v: Vec (int), e: int): bool { + (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'address'(ReadVec(v, i), e)) +} + +function $IndexOfVec'address'(v: Vec (int), e: int): int; +axiom (forall v: Vec (int), e: int:: {$IndexOfVec'address'(v, e)} + (var i := $IndexOfVec'address'(v, e); + if (!$ContainsVec'address'(v, e)) then i == -1 + else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'address'(ReadVec(v, i), e) && + (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'address'(ReadVec(v, j), e)))); + + +function {:inline} $RangeVec'address'(v: Vec (int)): $Range { + $Range(0, LenVec(v)) +} + + +function {:inline} $EmptyVec'address'(): Vec (int) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_empty'address'() returns (v: Vec (int)) { + v := EmptyVec(); +} + +function {:inline} $1_vector_$empty'address'(): Vec (int) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_is_empty'address'(v: Vec (int)) returns (b: bool) { + b := IsEmptyVec(v); +} + +procedure {:inline 1} $1_vector_push_back'address'(m: $Mutation (Vec (int)), val: int) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); +} + +function {:inline} $1_vector_$push_back'address'(v: Vec (int), val: int): Vec (int) { + ExtendVec(v, val) +} + +procedure {:inline 1} $1_vector_pop_back'address'(m: $Mutation (Vec (int))) returns (e: int, m': $Mutation (Vec (int))) { + var v: Vec (int); + var len: int; + v := $Dereference(m); + len := LenVec(v); + if (len == 0) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, len-1); + m' := $UpdateMutation(m, RemoveVec(v)); +} + +procedure {:inline 1} $1_vector_append'address'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); +} + +procedure {:inline 1} $1_vector_reverse'address'(m: $Mutation (Vec (int))) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ReverseVec($Dereference(m))); +} + +procedure {:inline 1} $1_vector_reverse_append'address'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); +} + +procedure {:inline 1} $1_vector_trim_reverse'address'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + v := ReverseVec(v); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_trim'address'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_reverse_slice'address'(m: $Mutation (Vec (int)), left: int, right: int) returns (m': $Mutation (Vec (int))) { + var left_vec: Vec (int); + var mid_vec: Vec (int); + var right_vec: Vec (int); + var v: Vec (int); + if (left > right) { + call $ExecFailureAbort(); + return; + } + if (left == right) { + m' := m; + return; + } + v := $Dereference(m); + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_vec := ReverseVec(SliceVec(v, left, right)); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); +} + +procedure {:inline 1} $1_vector_rotate'address'(m: $Mutation (Vec (int)), rot: int) returns (n: int, m': $Mutation (Vec (int))) { + var v: Vec (int); + var len: int; + var left_vec: Vec (int); + var right_vec: Vec (int); + v := $Dereference(m); + if (!(rot >= 0 && rot <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, rot); + right_vec := SliceVec(v, rot, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); + n := LenVec(v) - rot; +} + +procedure {:inline 1} $1_vector_rotate_slice'address'(m: $Mutation (Vec (int)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (int))) { + var left_vec: Vec (int); + var mid_vec: Vec (int); + var right_vec: Vec (int); + var mid_left_vec: Vec (int); + var mid_right_vec: Vec (int); + var v: Vec (int); + v := $Dereference(m); + if (!(left <= rot && rot <= right)) { + call $ExecFailureAbort(); + return; + } + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + v := $Dereference(m); + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_left_vec := SliceVec(v, left, rot); + mid_right_vec := SliceVec(v, rot, right); + mid_vec := ConcatVec(mid_right_vec, mid_left_vec); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); + n := left + (right - rot); +} + +procedure {:inline 1} $1_vector_insert'address'(m: $Mutation (Vec (int)), i: int, e: int) returns (m': $Mutation (Vec (int))) { + var left_vec: Vec (int); + var right_vec: Vec (int); + var v: Vec (int); + v := $Dereference(m); + if (!(i >= 0 && i <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + if (i == LenVec(v)) { + m' := $UpdateMutation(m, ExtendVec(v, e)); + } else { + left_vec := ExtendVec(SliceVec(v, 0, i), e); + right_vec := SliceVec(v, i, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); + } +} + +procedure {:inline 1} $1_vector_length'address'(v: Vec (int)) returns (l: int) { + l := LenVec(v); +} + +function {:inline} $1_vector_$length'address'(v: Vec (int)): int { + LenVec(v) +} + +procedure {:inline 1} $1_vector_borrow'address'(v: Vec (int), i: int) returns (dst: int) { + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + dst := ReadVec(v, i); +} + +function {:inline} $1_vector_$borrow'address'(v: Vec (int), i: int): int { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_borrow_mut'address'(m: $Mutation (Vec (int)), index: int) +returns (dst: $Mutation (int), m': $Mutation (Vec (int))) +{ + var v: Vec (int); + v := $Dereference(m); + if (!InRangeVec(v, index)) { + call $ExecFailureAbort(); + return; + } + dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); + m' := m; +} + +function {:inline} $1_vector_$borrow_mut'address'(v: Vec (int), i: int): int { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_destroy_empty'address'(v: Vec (int)) { + if (!IsEmptyVec(v)) { + call $ExecFailureAbort(); + } +} + +procedure {:inline 1} $1_vector_swap'address'(m: $Mutation (Vec (int)), i: int, j: int) returns (m': $Mutation (Vec (int))) +{ + var v: Vec (int); + v := $Dereference(m); + if (!InRangeVec(v, i) || !InRangeVec(v, j)) { + call $ExecFailureAbort(); + return; + } + m' := $UpdateMutation(m, SwapVec(v, i, j)); +} + +function {:inline} $1_vector_$swap'address'(v: Vec (int), i: int, j: int): Vec (int) { + SwapVec(v, i, j) +} + +procedure {:inline 1} $1_vector_remove'address'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) +{ + var v: Vec (int); + + v := $Dereference(m); + + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveAtVec(v, i)); +} + +procedure {:inline 1} $1_vector_swap_remove'address'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) +{ + var len: int; + var v: Vec (int); + + v := $Dereference(m); + len := LenVec(v); + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); +} + +procedure {:inline 1} $1_vector_contains'address'(v: Vec (int), e: int) returns (res: bool) { + res := $ContainsVec'address'(v, e); +} + +procedure {:inline 1} +$1_vector_index_of'address'(v: Vec (int), e: int) returns (res1: bool, res2: int) { + res2 := $IndexOfVec'address'(v, e); + if (res2 >= 0) { + res1 := true; + } else { + res1 := false; + res2 := 0; + } +} + + +// ---------------------------------------------------------------------------------- +// Native Vector implementation for element type `u8` + +// Not inlined. It appears faster this way. +function $IsEqual'vec'u8''(v1: Vec (int), v2: Vec (int)): bool { + LenVec(v1) == LenVec(v2) && + (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'u8'(ReadVec(v1, i), ReadVec(v2, i))) +} + +// Not inlined. +function $IsPrefix'vec'u8''(v: Vec (int), prefix: Vec (int)): bool { + LenVec(v) >= LenVec(prefix) && + (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'u8'(ReadVec(v, i), ReadVec(prefix, i))) +} + +// Not inlined. +function $IsSuffix'vec'u8''(v: Vec (int), suffix: Vec (int)): bool { + LenVec(v) >= LenVec(suffix) && + (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'u8'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) +} + +// Not inlined. +function $IsValid'vec'u8''(v: Vec (int)): bool { + $IsValid'u64'(LenVec(v)) && + (forall i: int:: InRangeVec(v, i) ==> $IsValid'u8'(ReadVec(v, i))) +} + + +function {:inline} $ContainsVec'u8'(v: Vec (int), e: int): bool { + (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'u8'(ReadVec(v, i), e)) +} + +function $IndexOfVec'u8'(v: Vec (int), e: int): int; +axiom (forall v: Vec (int), e: int:: {$IndexOfVec'u8'(v, e)} + (var i := $IndexOfVec'u8'(v, e); + if (!$ContainsVec'u8'(v, e)) then i == -1 + else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'u8'(ReadVec(v, i), e) && + (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'u8'(ReadVec(v, j), e)))); + + +function {:inline} $RangeVec'u8'(v: Vec (int)): $Range { + $Range(0, LenVec(v)) +} + + +function {:inline} $EmptyVec'u8'(): Vec (int) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_empty'u8'() returns (v: Vec (int)) { + v := EmptyVec(); +} + +function {:inline} $1_vector_$empty'u8'(): Vec (int) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_is_empty'u8'(v: Vec (int)) returns (b: bool) { + b := IsEmptyVec(v); +} + +procedure {:inline 1} $1_vector_push_back'u8'(m: $Mutation (Vec (int)), val: int) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); +} + +function {:inline} $1_vector_$push_back'u8'(v: Vec (int), val: int): Vec (int) { + ExtendVec(v, val) +} + +procedure {:inline 1} $1_vector_pop_back'u8'(m: $Mutation (Vec (int))) returns (e: int, m': $Mutation (Vec (int))) { + var v: Vec (int); + var len: int; + v := $Dereference(m); + len := LenVec(v); + if (len == 0) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, len-1); + m' := $UpdateMutation(m, RemoveVec(v)); +} + +procedure {:inline 1} $1_vector_append'u8'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); +} + +procedure {:inline 1} $1_vector_reverse'u8'(m: $Mutation (Vec (int))) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ReverseVec($Dereference(m))); +} + +procedure {:inline 1} $1_vector_reverse_append'u8'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); +} + +procedure {:inline 1} $1_vector_trim_reverse'u8'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + v := ReverseVec(v); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_trim'u8'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_reverse_slice'u8'(m: $Mutation (Vec (int)), left: int, right: int) returns (m': $Mutation (Vec (int))) { + var left_vec: Vec (int); + var mid_vec: Vec (int); + var right_vec: Vec (int); + var v: Vec (int); + if (left > right) { + call $ExecFailureAbort(); + return; + } + if (left == right) { + m' := m; + return; + } + v := $Dereference(m); + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_vec := ReverseVec(SliceVec(v, left, right)); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); +} + +procedure {:inline 1} $1_vector_rotate'u8'(m: $Mutation (Vec (int)), rot: int) returns (n: int, m': $Mutation (Vec (int))) { + var v: Vec (int); + var len: int; + var left_vec: Vec (int); + var right_vec: Vec (int); + v := $Dereference(m); + if (!(rot >= 0 && rot <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, rot); + right_vec := SliceVec(v, rot, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); + n := LenVec(v) - rot; +} + +procedure {:inline 1} $1_vector_rotate_slice'u8'(m: $Mutation (Vec (int)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (int))) { + var left_vec: Vec (int); + var mid_vec: Vec (int); + var right_vec: Vec (int); + var mid_left_vec: Vec (int); + var mid_right_vec: Vec (int); + var v: Vec (int); + v := $Dereference(m); + if (!(left <= rot && rot <= right)) { + call $ExecFailureAbort(); + return; + } + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + v := $Dereference(m); + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_left_vec := SliceVec(v, left, rot); + mid_right_vec := SliceVec(v, rot, right); + mid_vec := ConcatVec(mid_right_vec, mid_left_vec); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); + n := left + (right - rot); +} + +procedure {:inline 1} $1_vector_insert'u8'(m: $Mutation (Vec (int)), i: int, e: int) returns (m': $Mutation (Vec (int))) { + var left_vec: Vec (int); + var right_vec: Vec (int); + var v: Vec (int); + v := $Dereference(m); + if (!(i >= 0 && i <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + if (i == LenVec(v)) { + m' := $UpdateMutation(m, ExtendVec(v, e)); + } else { + left_vec := ExtendVec(SliceVec(v, 0, i), e); + right_vec := SliceVec(v, i, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); + } +} + +procedure {:inline 1} $1_vector_length'u8'(v: Vec (int)) returns (l: int) { + l := LenVec(v); +} + +function {:inline} $1_vector_$length'u8'(v: Vec (int)): int { + LenVec(v) +} + +procedure {:inline 1} $1_vector_borrow'u8'(v: Vec (int), i: int) returns (dst: int) { + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + dst := ReadVec(v, i); +} + +function {:inline} $1_vector_$borrow'u8'(v: Vec (int), i: int): int { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_borrow_mut'u8'(m: $Mutation (Vec (int)), index: int) +returns (dst: $Mutation (int), m': $Mutation (Vec (int))) +{ + var v: Vec (int); + v := $Dereference(m); + if (!InRangeVec(v, index)) { + call $ExecFailureAbort(); + return; + } + dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); + m' := m; +} + +function {:inline} $1_vector_$borrow_mut'u8'(v: Vec (int), i: int): int { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_destroy_empty'u8'(v: Vec (int)) { + if (!IsEmptyVec(v)) { + call $ExecFailureAbort(); + } +} + +procedure {:inline 1} $1_vector_swap'u8'(m: $Mutation (Vec (int)), i: int, j: int) returns (m': $Mutation (Vec (int))) +{ + var v: Vec (int); + v := $Dereference(m); + if (!InRangeVec(v, i) || !InRangeVec(v, j)) { + call $ExecFailureAbort(); + return; + } + m' := $UpdateMutation(m, SwapVec(v, i, j)); +} + +function {:inline} $1_vector_$swap'u8'(v: Vec (int), i: int, j: int): Vec (int) { + SwapVec(v, i, j) +} + +procedure {:inline 1} $1_vector_remove'u8'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) +{ + var v: Vec (int); + + v := $Dereference(m); + + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveAtVec(v, i)); +} + +procedure {:inline 1} $1_vector_swap_remove'u8'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) +{ + var len: int; + var v: Vec (int); + + v := $Dereference(m); + len := LenVec(v); + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); +} + +procedure {:inline 1} $1_vector_contains'u8'(v: Vec (int), e: int) returns (res: bool) { + res := $ContainsVec'u8'(v, e); +} + +procedure {:inline 1} +$1_vector_index_of'u8'(v: Vec (int), e: int) returns (res1: bool, res2: int) { + res2 := $IndexOfVec'u8'(v, e); + if (res2 >= 0) { + res1 := true; + } else { + res1 := false; + res2 := 0; + } +} + + +// ---------------------------------------------------------------------------------- +// Native Vector implementation for element type `bv8` + +// Not inlined. It appears faster this way. +function $IsEqual'vec'bv8''(v1: Vec (bv8), v2: Vec (bv8)): bool { + LenVec(v1) == LenVec(v2) && + (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'bv8'(ReadVec(v1, i), ReadVec(v2, i))) +} + +// Not inlined. +function $IsPrefix'vec'bv8''(v: Vec (bv8), prefix: Vec (bv8)): bool { + LenVec(v) >= LenVec(prefix) && + (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'bv8'(ReadVec(v, i), ReadVec(prefix, i))) +} + +// Not inlined. +function $IsSuffix'vec'bv8''(v: Vec (bv8), suffix: Vec (bv8)): bool { + LenVec(v) >= LenVec(suffix) && + (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'bv8'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) +} + +// Not inlined. +function $IsValid'vec'bv8''(v: Vec (bv8)): bool { + $IsValid'u64'(LenVec(v)) && + (forall i: int:: InRangeVec(v, i) ==> $IsValid'bv8'(ReadVec(v, i))) +} + + +function {:inline} $ContainsVec'bv8'(v: Vec (bv8), e: bv8): bool { + (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'bv8'(ReadVec(v, i), e)) +} + +function $IndexOfVec'bv8'(v: Vec (bv8), e: bv8): int; +axiom (forall v: Vec (bv8), e: bv8:: {$IndexOfVec'bv8'(v, e)} + (var i := $IndexOfVec'bv8'(v, e); + if (!$ContainsVec'bv8'(v, e)) then i == -1 + else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'bv8'(ReadVec(v, i), e) && + (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'bv8'(ReadVec(v, j), e)))); + + +function {:inline} $RangeVec'bv8'(v: Vec (bv8)): $Range { + $Range(0, LenVec(v)) +} + + +function {:inline} $EmptyVec'bv8'(): Vec (bv8) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_empty'bv8'() returns (v: Vec (bv8)) { + v := EmptyVec(); +} + +function {:inline} $1_vector_$empty'bv8'(): Vec (bv8) { + EmptyVec() +} + +procedure {:inline 1} $1_vector_is_empty'bv8'(v: Vec (bv8)) returns (b: bool) { + b := IsEmptyVec(v); +} + +procedure {:inline 1} $1_vector_push_back'bv8'(m: $Mutation (Vec (bv8)), val: bv8) returns (m': $Mutation (Vec (bv8))) { + m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); +} + +function {:inline} $1_vector_$push_back'bv8'(v: Vec (bv8), val: bv8): Vec (bv8) { + ExtendVec(v, val) +} + +procedure {:inline 1} $1_vector_pop_back'bv8'(m: $Mutation (Vec (bv8))) returns (e: bv8, m': $Mutation (Vec (bv8))) { + var v: Vec (bv8); + var len: int; + v := $Dereference(m); + len := LenVec(v); + if (len == 0) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, len-1); + m' := $UpdateMutation(m, RemoveVec(v)); +} + +procedure {:inline 1} $1_vector_append'bv8'(m: $Mutation (Vec (bv8)), other: Vec (bv8)) returns (m': $Mutation (Vec (bv8))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); +} + +procedure {:inline 1} $1_vector_reverse'bv8'(m: $Mutation (Vec (bv8))) returns (m': $Mutation (Vec (bv8))) { + m' := $UpdateMutation(m, ReverseVec($Dereference(m))); +} + +procedure {:inline 1} $1_vector_reverse_append'bv8'(m: $Mutation (Vec (bv8)), other: Vec (bv8)) returns (m': $Mutation (Vec (bv8))) { + m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); +} + +procedure {:inline 1} $1_vector_trim_reverse'bv8'(m: $Mutation (Vec (bv8)), new_len: int) returns (v: (Vec (bv8)), m': $Mutation (Vec (bv8))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + v := ReverseVec(v); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_trim'bv8'(m: $Mutation (Vec (bv8)), new_len: int) returns (v: (Vec (bv8)), m': $Mutation (Vec (bv8))) { + var len: int; + v := $Dereference(m); + if (LenVec(v) < new_len) { + call $ExecFailureAbort(); + return; + } + v := SliceVec(v, new_len, LenVec(v)); + m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); +} + +procedure {:inline 1} $1_vector_reverse_slice'bv8'(m: $Mutation (Vec (bv8)), left: int, right: int) returns (m': $Mutation (Vec (bv8))) { + var left_vec: Vec (bv8); + var mid_vec: Vec (bv8); + var right_vec: Vec (bv8); + var v: Vec (bv8); + if (left > right) { + call $ExecFailureAbort(); + return; + } + if (left == right) { + m' := m; + return; + } + v := $Dereference(m); + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_vec := ReverseVec(SliceVec(v, left, right)); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); +} + +procedure {:inline 1} $1_vector_rotate'bv8'(m: $Mutation (Vec (bv8)), rot: int) returns (n: int, m': $Mutation (Vec (bv8))) { + var v: Vec (bv8); + var len: int; + var left_vec: Vec (bv8); + var right_vec: Vec (bv8); + v := $Dereference(m); + if (!(rot >= 0 && rot <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + left_vec := SliceVec(v, 0, rot); + right_vec := SliceVec(v, rot, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); + n := LenVec(v) - rot; +} + +procedure {:inline 1} $1_vector_rotate_slice'bv8'(m: $Mutation (Vec (bv8)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (bv8))) { + var left_vec: Vec (bv8); + var mid_vec: Vec (bv8); + var right_vec: Vec (bv8); + var mid_left_vec: Vec (bv8); + var mid_right_vec: Vec (bv8); + var v: Vec (bv8); + v := $Dereference(m); + if (!(left <= rot && rot <= right)) { + call $ExecFailureAbort(); + return; + } + if (!(right >= 0 && right <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + v := $Dereference(m); + left_vec := SliceVec(v, 0, left); + right_vec := SliceVec(v, right, LenVec(v)); + mid_left_vec := SliceVec(v, left, rot); + mid_right_vec := SliceVec(v, rot, right); + mid_vec := ConcatVec(mid_right_vec, mid_left_vec); + m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); + n := left + (right - rot); +} + +procedure {:inline 1} $1_vector_insert'bv8'(m: $Mutation (Vec (bv8)), i: int, e: bv8) returns (m': $Mutation (Vec (bv8))) { + var left_vec: Vec (bv8); + var right_vec: Vec (bv8); + var v: Vec (bv8); + v := $Dereference(m); + if (!(i >= 0 && i <= LenVec(v))) { + call $ExecFailureAbort(); + return; + } + if (i == LenVec(v)) { + m' := $UpdateMutation(m, ExtendVec(v, e)); + } else { + left_vec := ExtendVec(SliceVec(v, 0, i), e); + right_vec := SliceVec(v, i, LenVec(v)); + m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); + } +} + +procedure {:inline 1} $1_vector_length'bv8'(v: Vec (bv8)) returns (l: int) { + l := LenVec(v); +} + +function {:inline} $1_vector_$length'bv8'(v: Vec (bv8)): int { + LenVec(v) +} + +procedure {:inline 1} $1_vector_borrow'bv8'(v: Vec (bv8), i: int) returns (dst: bv8) { + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + dst := ReadVec(v, i); +} + +function {:inline} $1_vector_$borrow'bv8'(v: Vec (bv8), i: int): bv8 { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_borrow_mut'bv8'(m: $Mutation (Vec (bv8)), index: int) +returns (dst: $Mutation (bv8), m': $Mutation (Vec (bv8))) +{ + var v: Vec (bv8); + v := $Dereference(m); + if (!InRangeVec(v, index)) { + call $ExecFailureAbort(); + return; + } + dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); + m' := m; +} + +function {:inline} $1_vector_$borrow_mut'bv8'(v: Vec (bv8), i: int): bv8 { + ReadVec(v, i) +} + +procedure {:inline 1} $1_vector_destroy_empty'bv8'(v: Vec (bv8)) { + if (!IsEmptyVec(v)) { + call $ExecFailureAbort(); + } +} + +procedure {:inline 1} $1_vector_swap'bv8'(m: $Mutation (Vec (bv8)), i: int, j: int) returns (m': $Mutation (Vec (bv8))) +{ + var v: Vec (bv8); + v := $Dereference(m); + if (!InRangeVec(v, i) || !InRangeVec(v, j)) { + call $ExecFailureAbort(); + return; + } + m' := $UpdateMutation(m, SwapVec(v, i, j)); +} + +function {:inline} $1_vector_$swap'bv8'(v: Vec (bv8), i: int, j: int): Vec (bv8) { + SwapVec(v, i, j) +} + +procedure {:inline 1} $1_vector_remove'bv8'(m: $Mutation (Vec (bv8)), i: int) returns (e: bv8, m': $Mutation (Vec (bv8))) +{ + var v: Vec (bv8); + + v := $Dereference(m); + + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveAtVec(v, i)); +} + +procedure {:inline 1} $1_vector_swap_remove'bv8'(m: $Mutation (Vec (bv8)), i: int) returns (e: bv8, m': $Mutation (Vec (bv8))) +{ + var len: int; + var v: Vec (bv8); + + v := $Dereference(m); + len := LenVec(v); + if (!InRangeVec(v, i)) { + call $ExecFailureAbort(); + return; + } + e := ReadVec(v, i); + m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); +} + +procedure {:inline 1} $1_vector_contains'bv8'(v: Vec (bv8), e: bv8) returns (res: bool) { + res := $ContainsVec'bv8'(v, e); +} + +procedure {:inline 1} +$1_vector_index_of'bv8'(v: Vec (bv8), e: bv8) returns (res1: bool, res2: int) { + res2 := $IndexOfVec'bv8'(v, e); + if (res2 >= 0) { + res1 := true; + } else { + res1 := false; + res2 := 0; + } +} + + +// ================================================================================== +// Native Table + +// ---------------------------------------------------------------------------------- +// Native Table key encoding for type `vec'u8'` + +function $EncodeKey'vec'u8''(k: Vec (int)): int; +axiom ( + forall k1, k2: Vec (int) :: {$EncodeKey'vec'u8''(k1), $EncodeKey'vec'u8''(k2)} + $IsEqual'vec'u8''(k1, k2) <==> $EncodeKey'vec'u8''(k1) == $EncodeKey'vec'u8''(k2) +); + + +// ---------------------------------------------------------------------------------- +// Native Table implementation for type `(vec'u8',$1_timelock_TimelockTransaction)` + +function $IsEqual'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(t1: Table int ($1_timelock_TimelockTransaction), t2: Table int ($1_timelock_TimelockTransaction)): bool { + LenTable(t1) == LenTable(t2) && + (forall k: int :: ContainsTable(t1, k) <==> ContainsTable(t2, k)) && + (forall k: int :: ContainsTable(t1, k) ==> GetTable(t1, k) == GetTable(t2, k)) && + (forall k: int :: ContainsTable(t2, k) ==> GetTable(t1, k) == GetTable(t2, k)) +} + +// Not inlined. +function $IsValid'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(t: Table int ($1_timelock_TimelockTransaction)): bool { + $IsValid'u64'(LenTable(t)) && + (forall i: int:: ContainsTable(t, i) ==> $IsValid'$1_timelock_TimelockTransaction'(GetTable(t, i))) +} +procedure {:inline 2} $1_table_new'vec'u8'_$1_timelock_TimelockTransaction'() returns (v: Table int ($1_timelock_TimelockTransaction)) { + v := EmptyTable(); +} +procedure {:inline 2} $1_table_destroy_known_empty_unsafe'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction)) { + if (LenTable(t) != 0) { + call $Abort($StdError(1/*INVALID_STATE*/, 102/*ENOT_EMPTY*/)); + } +} +procedure {:inline 2} $1_table_contains'vec'u8'_$1_timelock_TimelockTransaction'(t: (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)) returns (r: bool) { + r := ContainsTable(t, $EncodeKey'vec'u8''(k)); +} +procedure {:inline 2} $1_table_add'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int), v: $1_timelock_TimelockTransaction) returns (m': $Mutation(Table int ($1_timelock_TimelockTransaction))) { + var enc_k: int; + var t: Table int ($1_timelock_TimelockTransaction); + enc_k := $EncodeKey'vec'u8''(k); + t := $Dereference(m); + if (ContainsTable(t, enc_k)) { + call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 100/*EALREADY_EXISTS*/)); + } else { + m' := $UpdateMutation(m, AddTable(t, enc_k, v)); + } +} +procedure {:inline 2} $1_table_upsert'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int), v: $1_timelock_TimelockTransaction) returns (m': $Mutation(Table int ($1_timelock_TimelockTransaction))) { + var enc_k: int; + var t: Table int ($1_timelock_TimelockTransaction); + enc_k := $EncodeKey'vec'u8''(k); + t := $Dereference(m); + if (ContainsTable(t, enc_k)) { + m' := $UpdateMutation(m, UpdateTable(t, enc_k, v)); + } else { + m' := $UpdateMutation(m, AddTable(t, enc_k, v)); + } +} +procedure {:inline 2} $1_table_remove'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)) +returns (v: $1_timelock_TimelockTransaction, m': $Mutation(Table int ($1_timelock_TimelockTransaction))) { + var enc_k: int; + var t: Table int ($1_timelock_TimelockTransaction); + enc_k := $EncodeKey'vec'u8''(k); + t := $Dereference(m); + if (!ContainsTable(t, enc_k)) { + call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 101/*ENOT_FOUND*/)); + } else { + v := GetTable(t, enc_k); + m' := $UpdateMutation(m, RemoveTable(t, enc_k)); + } +} +procedure {:inline 2} $1_table_borrow'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int)) returns (v: $1_timelock_TimelockTransaction) { + var enc_k: int; + enc_k := $EncodeKey'vec'u8''(k); + if (!ContainsTable(t, enc_k)) { + call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 101/*ENOT_FOUND*/)); + } else { + v := GetTable(t, $EncodeKey'vec'u8''(k)); + } +} +procedure {:inline 2} $1_table_borrow_mut'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)) +returns (dst: $Mutation ($1_timelock_TimelockTransaction), m': $Mutation (Table int ($1_timelock_TimelockTransaction))) { + var enc_k: int; + var t: Table int ($1_timelock_TimelockTransaction); + enc_k := $EncodeKey'vec'u8''(k); + t := $Dereference(m); + if (!ContainsTable(t, enc_k)) { + call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 101/*ENOT_FOUND*/)); + } else { + dst := $Mutation(m->l, ExtendVec(m->p, enc_k), GetTable(t, enc_k)); + m' := m; + } +} +procedure {:inline 2} $1_table_borrow_mut_with_default'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int), default: $1_timelock_TimelockTransaction) +returns (dst: $Mutation ($1_timelock_TimelockTransaction), m': $Mutation (Table int ($1_timelock_TimelockTransaction))) { + var enc_k: int; + var t: Table int ($1_timelock_TimelockTransaction); + var t': Table int ($1_timelock_TimelockTransaction); + enc_k := $EncodeKey'vec'u8''(k); + t := $Dereference(m); + if (!ContainsTable(t, enc_k)) { + m' := $UpdateMutation(m, AddTable(t, enc_k, default)); + t' := $Dereference(m'); + dst := $Mutation(m'->l, ExtendVec(m'->p, enc_k), GetTable(t', enc_k)); + } else { + dst := $Mutation(m->l, ExtendVec(m->p, enc_k), GetTable(t, enc_k)); + m' := m; + } +} +procedure {:inline 2} $1_table_borrow_with_default'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int), default: $1_timelock_TimelockTransaction) returns (v: $1_timelock_TimelockTransaction) { + var enc_k: int; + enc_k := $EncodeKey'vec'u8''(k); + if (!ContainsTable(t, enc_k)) { + v := default; + } else { + v := GetTable(t, $EncodeKey'vec'u8''(k)); + } +} +function {:inline} $1_table_spec_contains'vec'u8'_$1_timelock_TimelockTransaction'(t: (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)): bool { + ContainsTable(t, $EncodeKey'vec'u8''(k)) +} +function {:inline} $1_table_spec_set'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int), v: $1_timelock_TimelockTransaction): Table int ($1_timelock_TimelockTransaction) { + (var enc_k := $EncodeKey'vec'u8''(k); + if (ContainsTable(t, enc_k)) then + UpdateTable(t, enc_k, v) + else + AddTable(t, enc_k, v)) +} +function {:inline} $1_table_spec_remove'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int)): Table int ($1_timelock_TimelockTransaction) { + RemoveTable(t, $EncodeKey'vec'u8''(k)) +} +function {:inline} $1_table_spec_get'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int)): $1_timelock_TimelockTransaction { + GetTable(t, $EncodeKey'vec'u8''(k)) +} + + + +// ================================================================================== +// Native Hash + +// Hash is modeled as an otherwise uninterpreted injection. +// In truth, it is not an injection since the domain has greater cardinality +// (arbitrary length vectors) than the co-domain (vectors of length 32). But it is +// common to assume in code there are no hash collisions in practice. Fortunately, +// Boogie is not smart enough to recognized that there is an inconsistency. +// FIXME: If we were using a reliable extensional theory of arrays, and if we could use == +// instead of $IsEqual, we might be able to avoid so many quantified formulas by +// using a sha2_inverse function in the ensures conditions of Hash_sha2_256 to +// assert that sha2/3 are injections without using global quantified axioms. + + +function $1_hash_sha2(val: Vec int): Vec int; + +// This says that Hash_sha2 is bijective. +axiom (forall v1,v2: Vec int :: {$1_hash_sha2(v1), $1_hash_sha2(v2)} + $IsEqual'vec'u8''(v1, v2) <==> $IsEqual'vec'u8''($1_hash_sha2(v1), $1_hash_sha2(v2))); + +procedure $1_hash_sha2_256(val: Vec int) returns (res: Vec int); +ensures res == $1_hash_sha2(val); // returns Hash_sha2 Value +ensures $IsValid'vec'u8''(res); // result is a legal vector of U8s. +ensures LenVec(res) == 32; // result is 32 bytes. + +// Spec version of Move native function. +function {:inline} $1_hash_$sha2_256(val: Vec int): Vec int { + $1_hash_sha2(val) +} + +// similarly for Hash_sha3 +function $1_hash_sha3(val: Vec int): Vec int; + +axiom (forall v1,v2: Vec int :: {$1_hash_sha3(v1), $1_hash_sha3(v2)} + $IsEqual'vec'u8''(v1, v2) <==> $IsEqual'vec'u8''($1_hash_sha3(v1), $1_hash_sha3(v2))); + +procedure $1_hash_sha3_256(val: Vec int) returns (res: Vec int); +ensures res == $1_hash_sha3(val); // returns Hash_sha3 Value +ensures $IsValid'vec'u8''(res); // result is a legal vector of U8s. +ensures LenVec(res) == 32; // result is 32 bytes. + +// Spec version of Move native function. +function {:inline} $1_hash_$sha3_256(val: Vec int): Vec int { + $1_hash_sha3(val) +} + +// ================================================================================== +// Native string + +// TODO: correct implementation of strings + +procedure {:inline 1} $1_string_internal_check_utf8(x: Vec int) returns (r: bool) { +} + +procedure {:inline 1} $1_string_internal_sub_string(x: Vec int, i: int, j: int) returns (r: Vec int) { +} + +procedure {:inline 1} $1_string_internal_index_of(x: Vec int, y: Vec int) returns (r: int) { +} + +procedure {:inline 1} $1_string_internal_is_char_boundary(x: Vec int, i: int) returns (r: bool) { +} + + + + +// ================================================================================== +// Native diem_account + +procedure {:inline 1} $1_DiemAccount_create_signer( + addr: int +) returns (signer: $signer) { + // A signer is currently identical to an address. + signer := $signer(addr); +} + +procedure {:inline 1} $1_DiemAccount_destroy_signer( + signer: $signer +) { + return; +} + +// ================================================================================== +// Native account + +procedure {:inline 1} $1_Account_create_signer( + addr: int +) returns (signer: $signer) { + // A signer is currently identical to an address. + signer := $signer(addr); +} + +// ================================================================================== +// Native Signer + +datatype $signer { + $signer($addr: int), + $permissioned_signer($addr: int, $permission_addr: int) +} + +function {:inline} $IsValid'signer'(s: $signer): bool { + if s is $signer then + $IsValid'address'(s->$addr) + else + $IsValid'address'(s->$addr) && + $IsValid'address'(s->$permission_addr) +} + +function {:inline} $IsEqual'signer'(s1: $signer, s2: $signer): bool { + if s1 is $signer && s2 is $signer then + s1 == s2 + else if s1 is $permissioned_signer && s2 is $permissioned_signer then + s1 == s2 + else + false +} + +procedure {:inline 1} $1_signer_borrow_address(signer: $signer) returns (res: int) { + res := signer->$addr; +} + +function {:inline} $1_signer_$borrow_address(signer: $signer): int +{ + signer->$addr +} + +function $1_signer_is_txn_signer(s: $signer): bool; + +function $1_signer_is_txn_signer_addr(a: int): bool; + + +// ================================================================================== +// Native signature + +// Signature related functionality is handled via uninterpreted functions. This is sound +// currently because we verify every code path based on signature verification with +// an arbitrary interpretation. + +function $1_Signature_$ed25519_validate_pubkey(public_key: Vec int): bool; +function $1_Signature_$ed25519_verify(signature: Vec int, public_key: Vec int, message: Vec int): bool; + +// Needed because we do not have extensional equality: +axiom (forall k1, k2: Vec int :: + {$1_Signature_$ed25519_validate_pubkey(k1), $1_Signature_$ed25519_validate_pubkey(k2)} + $IsEqual'vec'u8''(k1, k2) ==> $1_Signature_$ed25519_validate_pubkey(k1) == $1_Signature_$ed25519_validate_pubkey(k2)); +axiom (forall s1, s2, k1, k2, m1, m2: Vec int :: + {$1_Signature_$ed25519_verify(s1, k1, m1), $1_Signature_$ed25519_verify(s2, k2, m2)} + $IsEqual'vec'u8''(s1, s2) && $IsEqual'vec'u8''(k1, k2) && $IsEqual'vec'u8''(m1, m2) + ==> $1_Signature_$ed25519_verify(s1, k1, m1) == $1_Signature_$ed25519_verify(s2, k2, m2)); + + +procedure {:inline 1} $1_Signature_ed25519_validate_pubkey(public_key: Vec int) returns (res: bool) { + res := $1_Signature_$ed25519_validate_pubkey(public_key); +} + +procedure {:inline 1} $1_Signature_ed25519_verify( + signature: Vec int, public_key: Vec int, message: Vec int) returns (res: bool) { + res := $1_Signature_$ed25519_verify(signature, public_key, message); +} + + +// ================================================================================== +// Native bcs::serialize + +// ---------------------------------------------------------------------------------- +// Native BCS implementation for element type `u64` + +// Serialize is modeled as an uninterpreted function, with an additional +// axiom to say it's an injection. + +function $1_bcs_serialize'u64'(v: int): Vec int; + +axiom (forall v1, v2: int :: {$1_bcs_serialize'u64'(v1), $1_bcs_serialize'u64'(v2)} + $IsEqual'u64'(v1, v2) <==> $IsEqual'vec'u8''($1_bcs_serialize'u64'(v1), $1_bcs_serialize'u64'(v2))); + +// This says that serialize returns a non-empty vec + +axiom (forall v: int :: {$1_bcs_serialize'u64'(v)} + ( var r := $1_bcs_serialize'u64'(v); $IsValid'vec'u8''(r) && LenVec(r) > 0 )); + + +procedure $1_bcs_to_bytes'u64'(v: int) returns (res: Vec int); +ensures res == $1_bcs_serialize'u64'(v); + +function {:inline} $1_bcs_$to_bytes'u64'(v: int): Vec int { + $1_bcs_serialize'u64'(v) +} + + + + + +// ================================================================================== +// Native Event module + + + +procedure {:inline 1} $InitEventStore() { +} + +// ============================================================================================ +// Type Reflection on Type Parameters + +datatype $TypeParamInfo { + $TypeParamBool(), + $TypeParamU8(), + $TypeParamU16(), + $TypeParamU32(), + $TypeParamU64(), + $TypeParamU128(), + $TypeParamU256(), + $TypeParamAddress(), + $TypeParamSigner(), + $TypeParamVector(e: $TypeParamInfo), + $TypeParamStruct(a: int, m: Vec int, s: Vec int) +} + + + +//================================== +// Begin Translation + +function $TypeName(t: $TypeParamInfo): Vec int; +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamBool ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 98][1 := 111][2 := 111][3 := 108], 4))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 98][1 := 111][2 := 111][3 := 108], 4)) ==> t is $TypeParamBool); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU8 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 56], 2))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 56], 2)) ==> t is $TypeParamU8); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU16 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 54], 3))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 54], 3)) ==> t is $TypeParamU16); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU32 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 51][2 := 50], 3))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 51][2 := 50], 3)) ==> t is $TypeParamU32); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU64 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 54][2 := 52], 3))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 54][2 := 52], 3)) ==> t is $TypeParamU64); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU128 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 50][3 := 56], 4))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 50][3 := 56], 4)) ==> t is $TypeParamU128); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU256 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 50][2 := 53][3 := 54], 4))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 50][2 := 53][3 := 54], 4)) ==> t is $TypeParamU256); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamAddress ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 97][1 := 100][2 := 100][3 := 114][4 := 101][5 := 115][6 := 115], 7))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 97][1 := 100][2 := 100][3 := 114][4 := 101][5 := 115][6 := 115], 7)) ==> t is $TypeParamAddress); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamSigner ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 115][1 := 105][2 := 103][3 := 110][4 := 101][5 := 114], 6))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 115][1 := 105][2 := 103][3 := 110][4 := 101][5 := 114], 6)) ==> t is $TypeParamSigner); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamVector ==> $IsEqual'vec'u8''($TypeName(t), ConcatVec(ConcatVec(Vec(DefaultVecMap()[0 := 118][1 := 101][2 := 99][3 := 116][4 := 111][5 := 114][6 := 60], 7), $TypeName(t->e)), Vec(DefaultVecMap()[0 := 62], 1)))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} ($IsPrefix'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 118][1 := 101][2 := 99][3 := 116][4 := 111][5 := 114][6 := 60], 7)) && $IsSuffix'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 62], 1))) ==> t is $TypeParamVector); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamStruct ==> $IsEqual'vec'u8''($TypeName(t), ConcatVec(ConcatVec(ConcatVec(ConcatVec(ConcatVec(Vec(DefaultVecMap()[0 := 48][1 := 120], 2), MakeVec1(t->a)), Vec(DefaultVecMap()[0 := 58][1 := 58], 2)), t->m), Vec(DefaultVecMap()[0 := 58][1 := 58], 2)), t->s))); +axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsPrefix'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 48][1 := 120], 2)) ==> t is $TypeParamVector); + + +// Given Types for Type Parameters + +type #0; +function {:inline} $IsEqual'#0'(x1: #0, x2: #0): bool { x1 == x2 } +function {:inline} $IsValid'#0'(x: #0): bool { true } +var #0_info: $TypeParamInfo; +var #0_$memory: $Memory #0; + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'bool'(b1), $1_from_bcs_deserializable'bool'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'u8'(b1), $1_from_bcs_deserializable'u8'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'u64'(b1), $1_from_bcs_deserializable'u64'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'u256'(b1), $1_from_bcs_deserializable'u256'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance
+axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'address'(b1), $1_from_bcs_deserializable'address'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'signer'(b1), $1_from_bcs_deserializable'signer'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance > +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'vec'u8''(b1), $1_from_bcs_deserializable'vec'u8''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance > +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'vec'address''(b1), $1_from_bcs_deserializable'vec'address''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance > +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'vec'#0''(b1), $1_from_bcs_deserializable'vec'#0''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::option::Option
> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_option_Option'address''(b1), $1_from_bcs_deserializable'$1_option_Option'address''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::features::Features> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_features_Features'(b1), $1_from_bcs_deserializable'$1_features_Features'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::type_info::TypeInfo> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_type_info_TypeInfo'(b1), $1_from_bcs_deserializable'$1_type_info_TypeInfo'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::table::Table, 0x1::timelock::TimelockTransaction>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b1), $1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::chain_status::GenesisEndMarker> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(b1), $1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timestamp::CurrentTimeMicroseconds> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(b1), $1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::permissioned_signer::GrantedPermissionHandles> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(b1), $1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::guid::GUID> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_guid_GUID'(b1), $1_from_bcs_deserializable'$1_guid_GUID'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::guid::ID> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_guid_ID'(b1), $1_from_bcs_deserializable'$1_guid_ID'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::event::EventHandle<0x1::account::CoinRegisterEvent>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b1), $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::event::EventHandle<0x1::account::KeyRotationEvent>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(b1), $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::event::EventHandle<0x1::reconfiguration::NewEpochEvent>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b1), $1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::Account> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_Account'(b1), $1_from_bcs_deserializable'$1_account_Account'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::CapabilityOffer<0x1::account::RotationCapability>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(b1), $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::CapabilityOffer<0x1::account::SignerCapability>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(b1), $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::SignerCapability> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_SignerCapability'(b1), $1_from_bcs_deserializable'$1_account_SignerCapability'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::reconfiguration::Configuration> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_reconfiguration_Configuration'(b1), $1_from_bcs_deserializable'$1_reconfiguration_Configuration'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::CreateTransaction> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_CreateTransaction'(b1), $1_from_bcs_deserializable'$1_timelock_CreateTransaction'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::AddCreators> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_AddCreators'(b1), $1_from_bcs_deserializable'$1_timelock_AddCreators'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::AddExecutors> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_AddExecutors'(b1), $1_from_bcs_deserializable'$1_timelock_AddExecutors'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::CancelTransaction> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_CancelTransaction'(b1), $1_from_bcs_deserializable'$1_timelock_CancelTransaction'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::RemoveCreators> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_RemoveCreators'(b1), $1_from_bcs_deserializable'$1_timelock_RemoveCreators'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::RemoveExecutors> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(b1), $1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::TimelockAccount> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_TimelockAccount'(b1), $1_from_bcs_deserializable'$1_timelock_TimelockAccount'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::TimelockTransaction> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(b1), $1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::UpdateMinNumSecondsExecute> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(b1), $1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <#0> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'#0'(b1), $1_from_bcs_deserializable'#0'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserialize'bool'(b1), $1_from_bcs_deserialize'bool'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'u8'($1_from_bcs_deserialize'u8'(b1), $1_from_bcs_deserialize'u8'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'u64'($1_from_bcs_deserialize'u64'(b1), $1_from_bcs_deserialize'u64'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'u256'($1_from_bcs_deserialize'u256'(b1), $1_from_bcs_deserialize'u256'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance
+axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'address'($1_from_bcs_deserialize'address'(b1), $1_from_bcs_deserialize'address'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'signer'($1_from_bcs_deserialize'signer'(b1), $1_from_bcs_deserialize'signer'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance > +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'vec'u8''($1_from_bcs_deserialize'vec'u8''(b1), $1_from_bcs_deserialize'vec'u8''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance > +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'vec'address''($1_from_bcs_deserialize'vec'address''(b1), $1_from_bcs_deserialize'vec'address''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance > +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'vec'#0''($1_from_bcs_deserialize'vec'#0''(b1), $1_from_bcs_deserialize'vec'#0''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::option::Option
> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_option_Option'address''($1_from_bcs_deserialize'$1_option_Option'address''(b1), $1_from_bcs_deserialize'$1_option_Option'address''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::features::Features> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_features_Features'($1_from_bcs_deserialize'$1_features_Features'(b1), $1_from_bcs_deserialize'$1_features_Features'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::type_info::TypeInfo> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_type_info_TypeInfo'($1_from_bcs_deserialize'$1_type_info_TypeInfo'(b1), $1_from_bcs_deserialize'$1_type_info_TypeInfo'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::table::Table, 0x1::timelock::TimelockTransaction>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''($1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b1), $1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::chain_status::GenesisEndMarker> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_chain_status_GenesisEndMarker'($1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(b1), $1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timestamp::CurrentTimeMicroseconds> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timestamp_CurrentTimeMicroseconds'($1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(b1), $1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::permissioned_signer::GrantedPermissionHandles> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_permissioned_signer_GrantedPermissionHandles'($1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(b1), $1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::guid::GUID> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_guid_GUID'($1_from_bcs_deserialize'$1_guid_GUID'(b1), $1_from_bcs_deserialize'$1_guid_GUID'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::guid::ID> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_guid_ID'($1_from_bcs_deserialize'$1_guid_ID'(b1), $1_from_bcs_deserialize'$1_guid_ID'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::event::EventHandle<0x1::account::CoinRegisterEvent>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_event_EventHandle'$1_account_CoinRegisterEvent''($1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b1), $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::event::EventHandle<0x1::account::KeyRotationEvent>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_event_EventHandle'$1_account_KeyRotationEvent''($1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(b1), $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::event::EventHandle<0x1::reconfiguration::NewEpochEvent>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''($1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b1), $1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::Account> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_Account'($1_from_bcs_deserialize'$1_account_Account'(b1), $1_from_bcs_deserialize'$1_account_Account'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::CapabilityOffer<0x1::account::RotationCapability>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_CapabilityOffer'$1_account_RotationCapability''($1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(b1), $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::CapabilityOffer<0x1::account::SignerCapability>> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_CapabilityOffer'$1_account_SignerCapability''($1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(b1), $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::SignerCapability> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_SignerCapability'($1_from_bcs_deserialize'$1_account_SignerCapability'(b1), $1_from_bcs_deserialize'$1_account_SignerCapability'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::reconfiguration::Configuration> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_reconfiguration_Configuration'($1_from_bcs_deserialize'$1_reconfiguration_Configuration'(b1), $1_from_bcs_deserialize'$1_reconfiguration_Configuration'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::CreateTransaction> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_CreateTransaction'($1_from_bcs_deserialize'$1_timelock_CreateTransaction'(b1), $1_from_bcs_deserialize'$1_timelock_CreateTransaction'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::AddCreators> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_AddCreators'($1_from_bcs_deserialize'$1_timelock_AddCreators'(b1), $1_from_bcs_deserialize'$1_timelock_AddCreators'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::AddExecutors> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_AddExecutors'($1_from_bcs_deserialize'$1_timelock_AddExecutors'(b1), $1_from_bcs_deserialize'$1_timelock_AddExecutors'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::CancelTransaction> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_CancelTransaction'($1_from_bcs_deserialize'$1_timelock_CancelTransaction'(b1), $1_from_bcs_deserialize'$1_timelock_CancelTransaction'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::RemoveCreators> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_RemoveCreators'($1_from_bcs_deserialize'$1_timelock_RemoveCreators'(b1), $1_from_bcs_deserialize'$1_timelock_RemoveCreators'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::RemoveExecutors> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_RemoveExecutors'($1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(b1), $1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::TimelockAccount> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_TimelockAccount'($1_from_bcs_deserialize'$1_timelock_TimelockAccount'(b1), $1_from_bcs_deserialize'$1_timelock_TimelockAccount'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::TimelockTransaction> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_TimelockTransaction'($1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(b1), $1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::UpdateMinNumSecondsExecute> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_UpdateMinNumSecondsExecute'($1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(b1), $1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <#0> +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'#0'($1_from_bcs_deserialize'#0'(b1), $1_from_bcs_deserialize'#0'(b2))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/permissioned_signer.spec.move:5:9+288 +axiom (forall a: $1_permissioned_signer_GrantedPermissionHandles :: $IsValid'$1_permissioned_signer_GrantedPermissionHandles'(a) ==> ((var $range_0 := $Range(0, LenVec(a->$active_handles)); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var i := $i_1; +((var $range_2 := $Range(0, LenVec(a->$active_handles)); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var j := $i_3; +((!$IsEqual'num'(i, j) ==> !$IsEqual'address'(ReadVec(a->$active_handles, i), ReadVec(a->$active_handles, j))))))))))))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:8:9+113 +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_keccak256(b1), $1_aptos_hash_spec_keccak256(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:13:9+129 +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_sha2_512_internal(b1), $1_aptos_hash_spec_sha2_512_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:18:9+129 +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_sha3_512_internal(b1), $1_aptos_hash_spec_sha3_512_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:23:9+131 +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_ripemd160_internal(b1), $1_aptos_hash_spec_ripemd160_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); + +// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:28:9+135 +axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_blake2b_256_internal(b1), $1_aptos_hash_spec_blake2b_256_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); + +// struct option::Option
at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/option.move:7:5+81 +datatype $1_option_Option'address' { + $1_option_Option'address'($vec: Vec (int)) +} +function {:inline} $Update'$1_option_Option'address''_vec(s: $1_option_Option'address', x: Vec (int)): $1_option_Option'address' { + $1_option_Option'address'(x) +} +function $IsValid'$1_option_Option'address''(s: $1_option_Option'address'): bool { + $IsValid'vec'address''(s->$vec) +} +function {:inline} $IsEqual'$1_option_Option'address''(s1: $1_option_Option'address', s2: $1_option_Option'address'): bool { + $IsEqual'vec'address''(s1->$vec, s2->$vec)} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:26:5+77 +function {:inline} $1_signer_$address_of(s: $signer): int { + $1_signer_$borrow_address(s) +} + +// fun signer::address_of [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:26:5+77 +procedure {:inline 1} $1_signer_address_of(_$t0: $signer) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: int; + var $t0: $signer; + var $temp_0'address': int; + var $temp_0'signer': $signer; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[s]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:26:5+1 + assume {:print "$at(16,794,795)"} true; + assume {:print "$track_local(4,0,0):", $t0} $t0 == $t0; + + // $t1 := signer::borrow_address($t0) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:27:10+17 + assume {:print "$at(16,848,865)"} true; + call $t1 := $1_signer_borrow_address($t0); + if ($abort_flag) { + assume {:print "$at(16,848,865)"} true; + $t2 := $abort_code; + assume {:print "$track_abort(4,0):", $t2} $t2 == $t2; + goto L2; + } + + // trace_return[0]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:27:9+18 + assume {:print "$track_return(4,0,0):", $t1} $t1 == $t1; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 + assume {:print "$at(16,870,871)"} true; +L1: + + // return $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 + assume {:print "$at(16,870,871)"} true; + $ret0 := $t1; + return; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 +L2: + + // abort($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 + assume {:print "$at(16,870,871)"} true; + $abort_code := $t2; + $abort_flag := true; + return; + +} + +// fun error::already_exists [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:3+71 +procedure {:inline 1} $1_error_already_exists(_$t0: int) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: int; + var $t3: int; + var $t0: int; + var $temp_0'u64': int; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:3+1 + assume {:print "$at(11,3585,3586)"} true; + assume {:print "$track_local(5,1,0):", $t0} $t0 == $t0; + + // $t1 := 8 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:54+14 + $t1 := 8; + assume $IsValid'u64'($t1); + + // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 + assume {:print "$at(11,2844,2873)"} true; + assume ($t2 == $shlU64($t1, 16)); + + // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 + assume {:print "$at(11,3626,3654)"} true; + + // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 + assume $IsValid'u64'($t3); + + // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 + assume $IsEqual'u64'($t3, $t1); + + // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 + assume {:print "$track_return(5,1,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:73+1 +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:73+1 + assume {:print "$at(11,3655,3656)"} true; + $ret0 := $t3; + return; + +} + +// fun error::invalid_argument [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:3+76 +procedure {:inline 1} $1_error_invalid_argument(_$t0: int) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: int; + var $t3: int; + var $t0: int; + var $temp_0'u64': int; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:3+1 + assume {:print "$at(11,3082,3083)"} true; + assume {:print "$track_local(5,4,0):", $t0} $t0 == $t0; + + // $t1 := 1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:57+16 + $t1 := 1; + assume $IsValid'u64'($t1); + + // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 + assume {:print "$at(11,2844,2873)"} true; + assume ($t2 == $shlU64($t1, 16)); + + // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 + assume {:print "$at(11,3126,3156)"} true; + + // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 + assume $IsValid'u64'($t3); + + // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 + assume $IsEqual'u64'($t3, $t1); + + // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 + assume {:print "$track_return(5,4,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:78+1 +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:78+1 + assume {:print "$at(11,3157,3158)"} true; + $ret0 := $t3; + return; + +} + +// fun error::invalid_state [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:3+70 +procedure {:inline 1} $1_error_invalid_state(_$t0: int) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: int; + var $t3: int; + var $t0: int; + var $temp_0'u64': int; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:3+1 + assume {:print "$at(11,3232,3233)"} true; + assume {:print "$track_local(5,5,0):", $t0} $t0 == $t0; + + // $t1 := 3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:54+13 + $t1 := 3; + assume $IsValid'u64'($t1); + + // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 + assume {:print "$at(11,2844,2873)"} true; + assume ($t2 == $shlU64($t1, 16)); + + // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 + assume {:print "$at(11,3273,3300)"} true; + + // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 + assume $IsValid'u64'($t3); + + // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 + assume $IsEqual'u64'($t3, $t1); + + // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 + assume {:print "$track_return(5,5,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:72+1 +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:72+1 + assume {:print "$at(11,3301,3302)"} true; + $ret0 := $t3; + return; + +} + +// fun error::not_found [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:3+61 +procedure {:inline 1} $1_error_not_found(_$t0: int) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: int; + var $t3: int; + var $t0: int; + var $temp_0'u64': int; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:3+1 + assume {:print "$at(11,3461,3462)"} true; + assume {:print "$track_local(5,6,0):", $t0} $t0 == $t0; + + // $t1 := 6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:49+9 + $t1 := 6; + assume $IsValid'u64'($t1); + + // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 + assume {:print "$at(11,2844,2873)"} true; + assume ($t2 == $shlU64($t1, 16)); + + // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 + assume {:print "$at(11,3497,3520)"} true; + + // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 + assume $IsValid'u64'($t3); + + // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 + assume $IsEqual'u64'($t3, $t1); + + // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 + assume {:print "$track_return(5,6,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:63+1 +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:63+1 + assume {:print "$at(11,3521,3522)"} true; + $ret0 := $t3; + return; + +} + +// fun error::permission_denied [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:3+77 +procedure {:inline 1} $1_error_permission_denied(_$t0: int) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: int; + var $t3: int; + var $t0: int; + var $temp_0'u64': int; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:3+1 + assume {:print "$at(11,3381,3382)"} true; + assume {:print "$track_local(5,9,0):", $t0} $t0 == $t0; + + // $t1 := 5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:57+17 + $t1 := 5; + assume $IsValid'u64'($t1); + + // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 + assume {:print "$at(11,2844,2873)"} true; + assume ($t2 == $shlU64($t1, 16)); + + // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 + assume {:print "$at(11,3425,3456)"} true; + + // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 + assume $IsValid'u64'($t3); + + // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 + assume $IsEqual'u64'($t3, $t1); + + // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 + assume {:print "$track_return(5,9,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:79+1 +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:79+1 + assume {:print "$at(11,3457,3458)"} true; + $ret0 := $t3; + return; + +} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/configs/features.spec.move:61:10+40 +function $1_features_spec_is_enabled(feature: int): bool; +axiom (forall feature: int :: +(var $$res := $1_features_spec_is_enabled(feature); +$IsValid'bool'($$res))); + +// struct features::Features at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/configs/features.move:800:5+61 +datatype $1_features_Features { + $1_features_Features($features: Vec (bv8)) +} +function {:inline} $Update'$1_features_Features'_features(s: $1_features_Features, x: Vec (bv8)): $1_features_Features { + $1_features_Features(x) +} +function $IsValid'$1_features_Features'(s: $1_features_Features): bool { + $IsValid'vec'bv8''(s->$features) +} +function {:inline} $IsEqual'$1_features_Features'(s1: $1_features_Features, s2: $1_features_Features): bool { + $IsEqual'vec'bv8''(s1->$features, s2->$features)} +var $1_features_Features_$memory: $Memory $1_features_Features; + +// struct type_info::TypeInfo at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/type_info.move:19:5+145 +datatype $1_type_info_TypeInfo { + $1_type_info_TypeInfo($account_address: int, $module_name: Vec (int), $struct_name: Vec (int)) +} +function {:inline} $Update'$1_type_info_TypeInfo'_account_address(s: $1_type_info_TypeInfo, x: int): $1_type_info_TypeInfo { + $1_type_info_TypeInfo(x, s->$module_name, s->$struct_name) +} +function {:inline} $Update'$1_type_info_TypeInfo'_module_name(s: $1_type_info_TypeInfo, x: Vec (int)): $1_type_info_TypeInfo { + $1_type_info_TypeInfo(s->$account_address, x, s->$struct_name) +} +function {:inline} $Update'$1_type_info_TypeInfo'_struct_name(s: $1_type_info_TypeInfo, x: Vec (int)): $1_type_info_TypeInfo { + $1_type_info_TypeInfo(s->$account_address, s->$module_name, x) +} +function $IsValid'$1_type_info_TypeInfo'(s: $1_type_info_TypeInfo): bool { + $IsValid'address'(s->$account_address) + && $IsValid'vec'u8''(s->$module_name) + && $IsValid'vec'u8''(s->$struct_name) +} +function {:inline} $IsEqual'$1_type_info_TypeInfo'(s1: $1_type_info_TypeInfo, s2: $1_type_info_TypeInfo): bool { + $IsEqual'address'(s1->$account_address, s2->$account_address) + && $IsEqual'vec'u8''(s1->$module_name, s2->$module_name) + && $IsEqual'vec'u8''(s1->$struct_name, s2->$struct_name)} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'bool'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'bool'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'u8'(bytes: Vec (int)): int; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'u8'(bytes); +$IsValid'u8'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'u64'(bytes: Vec (int)): int; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'u64'(bytes); +$IsValid'u64'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'u256'(bytes: Vec (int)): int; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'u256'(bytes); +$IsValid'u256'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'address'(bytes: Vec (int)): int; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'address'(bytes); +$IsValid'address'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'signer'(bytes: Vec (int)): $signer; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'signer'(bytes); +$IsValid'signer'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'vec'u8''(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'vec'u8''(bytes); +$IsValid'vec'u8''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'vec'address''(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'vec'address''(bytes); +$IsValid'vec'address''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'vec'#0''(bytes: Vec (int)): Vec (#0); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'vec'#0''(bytes); +$IsValid'vec'#0''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_option_Option'address''(bytes: Vec (int)): $1_option_Option'address'; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_option_Option'address''(bytes); +$IsValid'$1_option_Option'address''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_features_Features'(bytes: Vec (int)): $1_features_Features; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_features_Features'(bytes); +$IsValid'$1_features_Features'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_type_info_TypeInfo'(bytes: Vec (int)): $1_type_info_TypeInfo; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_type_info_TypeInfo'(bytes); +$IsValid'$1_type_info_TypeInfo'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes: Vec (int)): Table int ($1_timelock_TimelockTransaction); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes); +$IsValid'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(bytes: Vec (int)): $1_chain_status_GenesisEndMarker; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(bytes); +$IsValid'$1_chain_status_GenesisEndMarker'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(bytes: Vec (int)): $1_timestamp_CurrentTimeMicroseconds; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(bytes); +$IsValid'$1_timestamp_CurrentTimeMicroseconds'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(bytes: Vec (int)): $1_permissioned_signer_GrantedPermissionHandles; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(bytes); +$IsValid'$1_permissioned_signer_GrantedPermissionHandles'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_guid_GUID'(bytes: Vec (int)): $1_guid_GUID; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_guid_GUID'(bytes); +$IsValid'$1_guid_GUID'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_guid_ID'(bytes: Vec (int)): $1_guid_ID; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_guid_ID'(bytes); +$IsValid'$1_guid_ID'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes: Vec (int)): $1_event_EventHandle'$1_account_CoinRegisterEvent'; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes); +$IsValid'$1_event_EventHandle'$1_account_CoinRegisterEvent''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes: Vec (int)): $1_event_EventHandle'$1_account_KeyRotationEvent'; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes); +$IsValid'$1_event_EventHandle'$1_account_KeyRotationEvent''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes: Vec (int)): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes); +$IsValid'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_account_Account'(bytes: Vec (int)): $1_account_Account; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_account_Account'(bytes); +$IsValid'$1_account_Account'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes: Vec (int)): $1_account_CapabilityOffer'$1_account_RotationCapability'; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes); +$IsValid'$1_account_CapabilityOffer'$1_account_RotationCapability''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes: Vec (int)): $1_account_CapabilityOffer'$1_account_SignerCapability'; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes); +$IsValid'$1_account_CapabilityOffer'$1_account_SignerCapability''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_account_SignerCapability'(bytes: Vec (int)): $1_account_SignerCapability; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_account_SignerCapability'(bytes); +$IsValid'$1_account_SignerCapability'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_reconfiguration_Configuration'(bytes: Vec (int)): $1_reconfiguration_Configuration; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_reconfiguration_Configuration'(bytes); +$IsValid'$1_reconfiguration_Configuration'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_CreateTransaction'(bytes: Vec (int)): $1_timelock_CreateTransaction; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_CreateTransaction'(bytes); +$IsValid'$1_timelock_CreateTransaction'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_AddCreators'(bytes: Vec (int)): $1_timelock_AddCreators; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_AddCreators'(bytes); +$IsValid'$1_timelock_AddCreators'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_AddExecutors'(bytes: Vec (int)): $1_timelock_AddExecutors; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_AddExecutors'(bytes); +$IsValid'$1_timelock_AddExecutors'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_CancelTransaction'(bytes: Vec (int)): $1_timelock_CancelTransaction; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_CancelTransaction'(bytes); +$IsValid'$1_timelock_CancelTransaction'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_RemoveCreators'(bytes: Vec (int)): $1_timelock_RemoveCreators; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_RemoveCreators'(bytes); +$IsValid'$1_timelock_RemoveCreators'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(bytes: Vec (int)): $1_timelock_RemoveExecutors; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(bytes); +$IsValid'$1_timelock_RemoveExecutors'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_TimelockAccount'(bytes: Vec (int)): $1_timelock_TimelockAccount; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_TimelockAccount'(bytes); +$IsValid'$1_timelock_TimelockAccount'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(bytes: Vec (int)): $1_timelock_TimelockTransaction; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(bytes); +$IsValid'$1_timelock_TimelockTransaction'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(bytes: Vec (int)): $1_timelock_UpdateMinNumSecondsExecute; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(bytes); +$IsValid'$1_timelock_UpdateMinNumSecondsExecute'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 +function $1_from_bcs_deserialize'#0'(bytes: Vec (int)): #0; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserialize'#0'(bytes); +$IsValid'#0'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'bool'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'bool'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'u8'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'u8'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'u64'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'u64'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'u256'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'u256'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'address'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'address'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'signer'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'signer'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'vec'u8''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'vec'u8''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'vec'address''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'vec'address''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'vec'#0''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'vec'#0''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_option_Option'address''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_option_Option'address''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_features_Features'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_features_Features'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_type_info_TypeInfo'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_type_info_TypeInfo'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_guid_GUID'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_guid_GUID'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_guid_ID'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_guid_ID'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_account_Account'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_account_Account'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_account_SignerCapability'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_account_SignerCapability'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_reconfiguration_Configuration'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_reconfiguration_Configuration'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_CreateTransaction'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_CreateTransaction'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_AddCreators'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_AddCreators'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_AddExecutors'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_AddExecutors'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_CancelTransaction'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_CancelTransaction'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_RemoveCreators'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_RemoveCreators'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_TimelockAccount'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_TimelockAccount'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 +function $1_from_bcs_deserializable'#0'(bytes: Vec (int)): bool; +axiom (forall bytes: Vec (int) :: +(var $$res := $1_from_bcs_deserializable'#0'(bytes); +$IsValid'bool'($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/chain_status.move:35:5+90 +function {:inline} $1_chain_status_$is_operating($1_chain_status_GenesisEndMarker_$memory: $Memory $1_chain_status_GenesisEndMarker): bool { + $ResourceExists($1_chain_status_GenesisEndMarker_$memory, 1) +} + +// struct chain_status::GenesisEndMarker at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/chain_status.move:12:5+34 +datatype $1_chain_status_GenesisEndMarker { + $1_chain_status_GenesisEndMarker($dummy_field: bool) +} +function {:inline} $Update'$1_chain_status_GenesisEndMarker'_dummy_field(s: $1_chain_status_GenesisEndMarker, x: bool): $1_chain_status_GenesisEndMarker { + $1_chain_status_GenesisEndMarker(x) +} +function $IsValid'$1_chain_status_GenesisEndMarker'(s: $1_chain_status_GenesisEndMarker): bool { + $IsValid'bool'(s->$dummy_field) +} +function {:inline} $IsEqual'$1_chain_status_GenesisEndMarker'(s1: $1_chain_status_GenesisEndMarker, s2: $1_chain_status_GenesisEndMarker): bool { + s1 == s2 +} +var $1_chain_status_GenesisEndMarker_$memory: $Memory $1_chain_status_GenesisEndMarker; + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.spec.move:57:10+111 +function {:inline} $1_timestamp_spec_now_microseconds($1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds): int { + $ResourceValue($1_timestamp_CurrentTimeMicroseconds_$memory, 1)->$microseconds +} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:61:5+153 +function {:inline} $1_timestamp_$now_microseconds($1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds): int { + $ResourceValue($1_timestamp_CurrentTimeMicroseconds_$memory, 1)->$microseconds +} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:67:5+123 +function {:inline} $1_timestamp_$now_seconds($1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds): int { + ($1_timestamp_$now_microseconds($1_timestamp_CurrentTimeMicroseconds_$memory) div 1000000) +} + +// struct timestamp::CurrentTimeMicroseconds at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:12:5+73 +datatype $1_timestamp_CurrentTimeMicroseconds { + $1_timestamp_CurrentTimeMicroseconds($microseconds: int) +} +function {:inline} $Update'$1_timestamp_CurrentTimeMicroseconds'_microseconds(s: $1_timestamp_CurrentTimeMicroseconds, x: int): $1_timestamp_CurrentTimeMicroseconds { + $1_timestamp_CurrentTimeMicroseconds(x) +} +function $IsValid'$1_timestamp_CurrentTimeMicroseconds'(s: $1_timestamp_CurrentTimeMicroseconds): bool { + $IsValid'u64'(s->$microseconds) +} +function {:inline} $IsEqual'$1_timestamp_CurrentTimeMicroseconds'(s1: $1_timestamp_CurrentTimeMicroseconds, s2: $1_timestamp_CurrentTimeMicroseconds): bool { + s1 == s2 +} +var $1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds; + +// fun timestamp::now_microseconds [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:61:5+153 +procedure {:inline 1} $1_timestamp_now_microseconds() returns ($ret0: int) +{ + // declare local variables + var $t0: int; + var $t1: $1_timestamp_CurrentTimeMicroseconds; + var $t2: int; + var $t3: int; + var $temp_0'u64': int; + + // bytecode translation starts here + // $t0 := 0x1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:48+16 + assume {:print "$at(220,2511,2527)"} true; + $t0 := 1; + assume $IsValid'address'($t0); + + // $t1 := get_global<0x1::timestamp::CurrentTimeMicroseconds>($t0) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:9+56 + if (!$ResourceExists($1_timestamp_CurrentTimeMicroseconds_$memory, $t0)) { + call $ExecFailureAbort(); + } else { + $t1 := $ResourceValue($1_timestamp_CurrentTimeMicroseconds_$memory, $t0); + } + if ($abort_flag) { + assume {:print "$at(220,2472,2528)"} true; + $t2 := $abort_code; + assume {:print "$track_abort(22,0):", $t2} $t2 == $t2; + goto L2; + } + + // $t3 := get_field<0x1::timestamp::CurrentTimeMicroseconds>.microseconds($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:9+69 + $t3 := $t1->$microseconds; + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:9+69 + assume {:print "$track_return(22,0,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 + assume {:print "$at(220,2546,2547)"} true; +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 + assume {:print "$at(220,2546,2547)"} true; + $ret0 := $t3; + return; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 +L2: + + // abort($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 + assume {:print "$at(220,2546,2547)"} true; + $abort_code := $t2; + $abort_flag := true; + return; + +} + +// fun timestamp::now_seconds [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:67:5+123 +procedure {:inline 1} $1_timestamp_now_seconds() returns ($ret0: int) +{ + // declare local variables + var $t0: int; + var $t1: int; + var $t2: int; + var $t3: int; + var $temp_0'u64': int; + + // bytecode translation starts here + // $t0 := timestamp::now_microseconds() on_abort goto L2 with $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:9+18 + assume {:print "$at(220,2680,2698)"} true; + call $t0 := $1_timestamp_now_microseconds(); + if ($abort_flag) { + assume {:print "$at(220,2680,2698)"} true; + $t1 := $abort_code; + assume {:print "$track_abort(22,1):", $t1} $t1 == $t1; + goto L2; + } + + // $t2 := 1000000 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:30+23 + $t2 := 1000000; + assume $IsValid'u64'($t2); + + // $t3 := /($t0, $t2) on_abort goto L2 with $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:9+44 + call $t3 := $Div($t0, $t2); + if ($abort_flag) { + assume {:print "$at(220,2680,2724)"} true; + $t1 := $abort_code; + assume {:print "$track_abort(22,1):", $t1} $t1 == $t1; + goto L2; + } + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:9+44 + assume {:print "$track_return(22,1,0):", $t3} $t3 == $t3; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 + assume {:print "$at(220,2729,2730)"} true; +L1: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 + assume {:print "$at(220,2729,2730)"} true; + $ret0 := $t3; + return; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 +L2: + + // abort($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 + assume {:print "$at(220,2729,2730)"} true; + $abort_code := $t1; + $abort_flag := true; + return; + +} + +// struct permissioned_signer::GrantedPermissionHandles at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/permissioned_signer.move:64:5+188 +datatype $1_permissioned_signer_GrantedPermissionHandles { + $1_permissioned_signer_GrantedPermissionHandles($active_handles: Vec (int)) +} +function {:inline} $Update'$1_permissioned_signer_GrantedPermissionHandles'_active_handles(s: $1_permissioned_signer_GrantedPermissionHandles, x: Vec (int)): $1_permissioned_signer_GrantedPermissionHandles { + $1_permissioned_signer_GrantedPermissionHandles(x) +} +function $IsValid'$1_permissioned_signer_GrantedPermissionHandles'(s: $1_permissioned_signer_GrantedPermissionHandles): bool { + $IsValid'vec'address''(s->$active_handles) +} +function {:inline} $IsEqual'$1_permissioned_signer_GrantedPermissionHandles'(s1: $1_permissioned_signer_GrantedPermissionHandles, s2: $1_permissioned_signer_GrantedPermissionHandles): bool { + $IsEqual'vec'address''(s1->$active_handles, s2->$active_handles)} +var $1_permissioned_signer_GrantedPermissionHandles_$memory: $Memory $1_permissioned_signer_GrantedPermissionHandles; + +// struct guid::GUID at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/guid.move:7:5+50 +datatype $1_guid_GUID { + $1_guid_GUID($id: $1_guid_ID) +} +function {:inline} $Update'$1_guid_GUID'_id(s: $1_guid_GUID, x: $1_guid_ID): $1_guid_GUID { + $1_guid_GUID(x) +} +function $IsValid'$1_guid_GUID'(s: $1_guid_GUID): bool { + $IsValid'$1_guid_ID'(s->$id) +} +function {:inline} $IsEqual'$1_guid_GUID'(s1: $1_guid_GUID, s2: $1_guid_GUID): bool { + s1 == s2 +} + +// struct guid::ID at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/guid.move:12:5+209 +datatype $1_guid_ID { + $1_guid_ID($creation_num: int, $addr: int) +} +function {:inline} $Update'$1_guid_ID'_creation_num(s: $1_guid_ID, x: int): $1_guid_ID { + $1_guid_ID(x, s->$addr) +} +function {:inline} $Update'$1_guid_ID'_addr(s: $1_guid_ID, x: int): $1_guid_ID { + $1_guid_ID(s->$creation_num, x) +} +function $IsValid'$1_guid_ID'(s: $1_guid_ID): bool { + $IsValid'u64'(s->$creation_num) + && $IsValid'address'(s->$addr) +} +function {:inline} $IsEqual'$1_guid_ID'(s1: $1_guid_ID, s2: $1_guid_ID): bool { + s1 == s2 +} + +// struct event::EventHandle<0x1::account::CoinRegisterEvent> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/event.move:37:5+224 +datatype $1_event_EventHandle'$1_account_CoinRegisterEvent' { + $1_event_EventHandle'$1_account_CoinRegisterEvent'($counter: int, $guid: $1_guid_GUID) +} +function {:inline} $Update'$1_event_EventHandle'$1_account_CoinRegisterEvent''_counter(s: $1_event_EventHandle'$1_account_CoinRegisterEvent', x: int): $1_event_EventHandle'$1_account_CoinRegisterEvent' { + $1_event_EventHandle'$1_account_CoinRegisterEvent'(x, s->$guid) +} +function {:inline} $Update'$1_event_EventHandle'$1_account_CoinRegisterEvent''_guid(s: $1_event_EventHandle'$1_account_CoinRegisterEvent', x: $1_guid_GUID): $1_event_EventHandle'$1_account_CoinRegisterEvent' { + $1_event_EventHandle'$1_account_CoinRegisterEvent'(s->$counter, x) +} +function $IsValid'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s: $1_event_EventHandle'$1_account_CoinRegisterEvent'): bool { + $IsValid'u64'(s->$counter) + && $IsValid'$1_guid_GUID'(s->$guid) +} +function {:inline} $IsEqual'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s1: $1_event_EventHandle'$1_account_CoinRegisterEvent', s2: $1_event_EventHandle'$1_account_CoinRegisterEvent'): bool { + s1 == s2 +} + +// struct event::EventHandle<0x1::account::KeyRotationEvent> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/event.move:37:5+224 +datatype $1_event_EventHandle'$1_account_KeyRotationEvent' { + $1_event_EventHandle'$1_account_KeyRotationEvent'($counter: int, $guid: $1_guid_GUID) +} +function {:inline} $Update'$1_event_EventHandle'$1_account_KeyRotationEvent''_counter(s: $1_event_EventHandle'$1_account_KeyRotationEvent', x: int): $1_event_EventHandle'$1_account_KeyRotationEvent' { + $1_event_EventHandle'$1_account_KeyRotationEvent'(x, s->$guid) +} +function {:inline} $Update'$1_event_EventHandle'$1_account_KeyRotationEvent''_guid(s: $1_event_EventHandle'$1_account_KeyRotationEvent', x: $1_guid_GUID): $1_event_EventHandle'$1_account_KeyRotationEvent' { + $1_event_EventHandle'$1_account_KeyRotationEvent'(s->$counter, x) +} +function $IsValid'$1_event_EventHandle'$1_account_KeyRotationEvent''(s: $1_event_EventHandle'$1_account_KeyRotationEvent'): bool { + $IsValid'u64'(s->$counter) + && $IsValid'$1_guid_GUID'(s->$guid) +} +function {:inline} $IsEqual'$1_event_EventHandle'$1_account_KeyRotationEvent''(s1: $1_event_EventHandle'$1_account_KeyRotationEvent', s2: $1_event_EventHandle'$1_account_KeyRotationEvent'): bool { + s1 == s2 +} + +// struct event::EventHandle<0x1::reconfiguration::NewEpochEvent> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/event.move:37:5+224 +datatype $1_event_EventHandle'$1_reconfiguration_NewEpochEvent' { + $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'($counter: int, $guid: $1_guid_GUID) +} +function {:inline} $Update'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''_counter(s: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent', x: int): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent' { + $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'(x, s->$guid) +} +function {:inline} $Update'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''_guid(s: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent', x: $1_guid_GUID): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent' { + $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'(s->$counter, x) +} +function $IsValid'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(s: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'): bool { + $IsValid'u64'(s->$counter) + && $IsValid'$1_guid_GUID'(s->$guid) +} +function {:inline} $IsEqual'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(s1: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent', s2: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'): bool { + s1 == s2 +} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.spec.move:598:10+77 +function $1_account_spec_create_resource_address(source: int, seed: Vec (int)): int; +axiom (forall source: int, seed: Vec (int) :: +(var $$res := $1_account_spec_create_resource_address(source, seed); +$IsValid'address'($$res))); + +// struct account::Account at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:61:5+401 +datatype $1_account_Account { + $1_account_Account($authentication_key: Vec (int), $sequence_number: int, $guid_creation_num: int, $coin_register_events: $1_event_EventHandle'$1_account_CoinRegisterEvent', $key_rotation_events: $1_event_EventHandle'$1_account_KeyRotationEvent', $rotation_capability_offer: $1_account_CapabilityOffer'$1_account_RotationCapability', $signer_capability_offer: $1_account_CapabilityOffer'$1_account_SignerCapability') +} +function {:inline} $Update'$1_account_Account'_authentication_key(s: $1_account_Account, x: Vec (int)): $1_account_Account { + $1_account_Account(x, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) +} +function {:inline} $Update'$1_account_Account'_sequence_number(s: $1_account_Account, x: int): $1_account_Account { + $1_account_Account(s->$authentication_key, x, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) +} +function {:inline} $Update'$1_account_Account'_guid_creation_num(s: $1_account_Account, x: int): $1_account_Account { + $1_account_Account(s->$authentication_key, s->$sequence_number, x, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) +} +function {:inline} $Update'$1_account_Account'_coin_register_events(s: $1_account_Account, x: $1_event_EventHandle'$1_account_CoinRegisterEvent'): $1_account_Account { + $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, x, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) +} +function {:inline} $Update'$1_account_Account'_key_rotation_events(s: $1_account_Account, x: $1_event_EventHandle'$1_account_KeyRotationEvent'): $1_account_Account { + $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, x, s->$rotation_capability_offer, s->$signer_capability_offer) +} +function {:inline} $Update'$1_account_Account'_rotation_capability_offer(s: $1_account_Account, x: $1_account_CapabilityOffer'$1_account_RotationCapability'): $1_account_Account { + $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, x, s->$signer_capability_offer) +} +function {:inline} $Update'$1_account_Account'_signer_capability_offer(s: $1_account_Account, x: $1_account_CapabilityOffer'$1_account_SignerCapability'): $1_account_Account { + $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, x) +} +function $IsValid'$1_account_Account'(s: $1_account_Account): bool { + $IsValid'vec'u8''(s->$authentication_key) + && $IsValid'u64'(s->$sequence_number) + && $IsValid'u64'(s->$guid_creation_num) + && $IsValid'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s->$coin_register_events) + && $IsValid'$1_event_EventHandle'$1_account_KeyRotationEvent''(s->$key_rotation_events) + && $IsValid'$1_account_CapabilityOffer'$1_account_RotationCapability''(s->$rotation_capability_offer) + && $IsValid'$1_account_CapabilityOffer'$1_account_SignerCapability''(s->$signer_capability_offer) +} +function {:inline} $IsEqual'$1_account_Account'(s1: $1_account_Account, s2: $1_account_Account): bool { + $IsEqual'vec'u8''(s1->$authentication_key, s2->$authentication_key) + && $IsEqual'u64'(s1->$sequence_number, s2->$sequence_number) + && $IsEqual'u64'(s1->$guid_creation_num, s2->$guid_creation_num) + && $IsEqual'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s1->$coin_register_events, s2->$coin_register_events) + && $IsEqual'$1_event_EventHandle'$1_account_KeyRotationEvent''(s1->$key_rotation_events, s2->$key_rotation_events) + && $IsEqual'$1_account_CapabilityOffer'$1_account_RotationCapability''(s1->$rotation_capability_offer, s2->$rotation_capability_offer) + && $IsEqual'$1_account_CapabilityOffer'$1_account_SignerCapability''(s1->$signer_capability_offer, s2->$signer_capability_offer)} +var $1_account_Account_$memory: $Memory $1_account_Account; + +// struct account::CapabilityOffer<0x1::account::RotationCapability> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:86:5+68 +datatype $1_account_CapabilityOffer'$1_account_RotationCapability' { + $1_account_CapabilityOffer'$1_account_RotationCapability'($for: $1_option_Option'address') +} +function {:inline} $Update'$1_account_CapabilityOffer'$1_account_RotationCapability''_for(s: $1_account_CapabilityOffer'$1_account_RotationCapability', x: $1_option_Option'address'): $1_account_CapabilityOffer'$1_account_RotationCapability' { + $1_account_CapabilityOffer'$1_account_RotationCapability'(x) +} +function $IsValid'$1_account_CapabilityOffer'$1_account_RotationCapability''(s: $1_account_CapabilityOffer'$1_account_RotationCapability'): bool { + $IsValid'$1_option_Option'address''(s->$for) +} +function {:inline} $IsEqual'$1_account_CapabilityOffer'$1_account_RotationCapability''(s1: $1_account_CapabilityOffer'$1_account_RotationCapability', s2: $1_account_CapabilityOffer'$1_account_RotationCapability'): bool { + $IsEqual'$1_option_Option'address''(s1->$for, s2->$for)} + +// struct account::CapabilityOffer<0x1::account::SignerCapability> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:86:5+68 +datatype $1_account_CapabilityOffer'$1_account_SignerCapability' { + $1_account_CapabilityOffer'$1_account_SignerCapability'($for: $1_option_Option'address') +} +function {:inline} $Update'$1_account_CapabilityOffer'$1_account_SignerCapability''_for(s: $1_account_CapabilityOffer'$1_account_SignerCapability', x: $1_option_Option'address'): $1_account_CapabilityOffer'$1_account_SignerCapability' { + $1_account_CapabilityOffer'$1_account_SignerCapability'(x) +} +function $IsValid'$1_account_CapabilityOffer'$1_account_SignerCapability''(s: $1_account_CapabilityOffer'$1_account_SignerCapability'): bool { + $IsValid'$1_option_Option'address''(s->$for) +} +function {:inline} $IsEqual'$1_account_CapabilityOffer'$1_account_SignerCapability''(s1: $1_account_CapabilityOffer'$1_account_SignerCapability', s2: $1_account_CapabilityOffer'$1_account_SignerCapability'): bool { + $IsEqual'$1_option_Option'address''(s1->$for, s2->$for)} + +// struct account::CoinRegisterEvent at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:76:5+77 +datatype $1_account_CoinRegisterEvent { + $1_account_CoinRegisterEvent($type_info: $1_type_info_TypeInfo) +} +function {:inline} $Update'$1_account_CoinRegisterEvent'_type_info(s: $1_account_CoinRegisterEvent, x: $1_type_info_TypeInfo): $1_account_CoinRegisterEvent { + $1_account_CoinRegisterEvent(x) +} +function $IsValid'$1_account_CoinRegisterEvent'(s: $1_account_CoinRegisterEvent): bool { + $IsValid'$1_type_info_TypeInfo'(s->$type_info) +} +function {:inline} $IsEqual'$1_account_CoinRegisterEvent'(s1: $1_account_CoinRegisterEvent, s2: $1_account_CoinRegisterEvent): bool { + $IsEqual'$1_type_info_TypeInfo'(s1->$type_info, s2->$type_info)} + +// struct account::KeyRotationEvent at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:71:5+135 +datatype $1_account_KeyRotationEvent { + $1_account_KeyRotationEvent($old_authentication_key: Vec (int), $new_authentication_key: Vec (int)) +} +function {:inline} $Update'$1_account_KeyRotationEvent'_old_authentication_key(s: $1_account_KeyRotationEvent, x: Vec (int)): $1_account_KeyRotationEvent { + $1_account_KeyRotationEvent(x, s->$new_authentication_key) +} +function {:inline} $Update'$1_account_KeyRotationEvent'_new_authentication_key(s: $1_account_KeyRotationEvent, x: Vec (int)): $1_account_KeyRotationEvent { + $1_account_KeyRotationEvent(s->$old_authentication_key, x) +} +function $IsValid'$1_account_KeyRotationEvent'(s: $1_account_KeyRotationEvent): bool { + $IsValid'vec'u8''(s->$old_authentication_key) + && $IsValid'vec'u8''(s->$new_authentication_key) +} +function {:inline} $IsEqual'$1_account_KeyRotationEvent'(s1: $1_account_KeyRotationEvent, s2: $1_account_KeyRotationEvent): bool { + $IsEqual'vec'u8''(s1->$old_authentication_key, s2->$old_authentication_key) + && $IsEqual'vec'u8''(s1->$new_authentication_key, s2->$new_authentication_key)} + +// struct account::RotationCapability at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:88:5+62 +datatype $1_account_RotationCapability { + $1_account_RotationCapability($account: int) +} +function {:inline} $Update'$1_account_RotationCapability'_account(s: $1_account_RotationCapability, x: int): $1_account_RotationCapability { + $1_account_RotationCapability(x) +} +function $IsValid'$1_account_RotationCapability'(s: $1_account_RotationCapability): bool { + $IsValid'address'(s->$account) +} +function {:inline} $IsEqual'$1_account_RotationCapability'(s1: $1_account_RotationCapability, s2: $1_account_RotationCapability): bool { + s1 == s2 +} + +// struct account::SignerCapability at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:90:5+60 +datatype $1_account_SignerCapability { + $1_account_SignerCapability($account: int) +} +function {:inline} $Update'$1_account_SignerCapability'_account(s: $1_account_SignerCapability, x: int): $1_account_SignerCapability { + $1_account_SignerCapability(x) +} +function $IsValid'$1_account_SignerCapability'(s: $1_account_SignerCapability): bool { + $IsValid'address'(s->$account) +} +function {:inline} $IsEqual'$1_account_SignerCapability'(s1: $1_account_SignerCapability, s2: $1_account_SignerCapability): bool { + s1 == s2 +} + +// fun account::get_sequence_number [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:384:5+328 +procedure {:inline 1} $1_account_get_sequence_number(_$t0: int) returns ($ret0: int) +{ + // declare local variables + var $t1: int; + var $t2: bool; + var $t3: $1_account_Account; + var $t4: int; + var $t5: int; + var $t6: bool; + var $t7: int; + var $t8: int; + var $t9: int; + var $t0: int; + var $temp_0'address': int; + var $temp_0'u64': int; + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[addr]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:384:5+1 + assume {:print "$at(98,18599,18600)"} true; + assume {:print "$track_local(39,16,0):", $t0} $t0 == $t0; + + // $t2 := exists<0x1::account::Account>($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:360:9+21 + assume {:print "$at(98,17757,17778)"} true; + $t2 := $ResourceExists($1_account_Account_$memory, $t0); + + // if ($t2) goto L1 else goto L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 + assume {:print "$at(98,18677,18921)"} true; + if ($t2) { goto L1; } else { goto L0; } + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+13 + assume {:print "$at(98,18721,18734)"} true; +L1: + + // $t3 := get_global<0x1::account::Account>($t0) on_abort goto L6 with $t4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+13 + assume {:print "$at(98,18721,18734)"} true; + if (!$ResourceExists($1_account_Account_$memory, $t0)) { + call $ExecFailureAbort(); + } else { + $t3 := $ResourceValue($1_account_Account_$memory, $t0); + } + if ($abort_flag) { + assume {:print "$at(98,18721,18734)"} true; + $t4 := $abort_code; + assume {:print "$track_abort(39,16):", $t4} $t4 == $t4; + goto L6; + } + + // $t5 := get_field<0x1::account::Account>.sequence_number($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+29 + $t5 := $t3->$sequence_number; + + // $t1 := $t5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+29 + $t1 := $t5; + + // trace_local[return]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+29 + assume {:print "$track_local(39,16,1):", $t5} $t5 == $t5; + + // label L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 + assume {:print "$at(98,18677,18921)"} true; +L4: + + // trace_return[0]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 + assume {:print "$at(98,18677,18921)"} true; + assume {:print "$track_return(39,16,0):", $t1} $t1 == $t1; + + // goto L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 + goto L5; + + // label L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 + assume {:print "$at(98,18770,18817)"} true; +L0: + + // $t6 := opaque begin: features::is_default_account_resource_enabled() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 + assume {:print "$at(98,18770,18817)"} true; + + // assume WellFormed($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 + assume $IsValid'bool'($t6); + + // assume Eq($t6, features::spec_is_enabled(91)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 + assume $IsEqual'bool'($t6, $1_features_spec_is_enabled(91)); + + // $t6 := opaque end: features::is_default_account_resource_enabled() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 + + // if ($t6) goto L3 else goto L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:16+155 + if ($t6) { goto L3; } else { goto L2; } + + // label L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 + assume {:print "$at(98,18833,18834)"} true; +L3: + + // $t7 := 0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 + assume {:print "$at(98,18833,18834)"} true; + $t7 := 0; + assume $IsValid'u64'($t7); + + // $t1 := $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 + $t1 := $t7; + + // trace_local[return]($t7) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 + assume {:print "$track_local(39,16,1):", $t7} $t7 == $t7; + + // goto L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 + goto L4; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:36+23 + assume {:print "$at(98,18887,18910)"} true; +L2: + + // $t8 := 2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:36+23 + assume {:print "$at(98,18887,18910)"} true; + $t8 := 2; + assume $IsValid'u64'($t8); + + // $t9 := error::not_found($t8) on_abort goto L6 with $t4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:19+41 + call $t9 := $1_error_not_found($t8); + if ($abort_flag) { + assume {:print "$at(98,18870,18911)"} true; + $t4 := $abort_code; + assume {:print "$track_abort(39,16):", $t4} $t4 == $t4; + goto L6; + } + + // trace_abort($t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:13+47 + assume {:print "$at(98,18864,18911)"} true; + assume {:print "$track_abort(39,16):", $t9} $t9 == $t9; + + // $t4 := move($t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:13+47 + $t4 := $t9; + + // goto L6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:13+47 + goto L6; + + // label L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 + assume {:print "$at(98,18926,18927)"} true; +L5: + + // return $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 + assume {:print "$at(98,18926,18927)"} true; + $ret0 := $t1; + return; + + // label L6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 +L6: + + // abort($t4) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 + assume {:print "$at(98,18926,18927)"} true; + $abort_code := $t4; + $abort_flag := true; + return; + +} + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:7:9+50 +function $1_aptos_hash_spec_keccak256(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_aptos_hash_spec_keccak256(bytes); +$IsValid'vec'u8''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:12:9+58 +function $1_aptos_hash_spec_sha2_512_internal(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_aptos_hash_spec_sha2_512_internal(bytes); +$IsValid'vec'u8''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:17:9+58 +function $1_aptos_hash_spec_sha3_512_internal(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_aptos_hash_spec_sha3_512_internal(bytes); +$IsValid'vec'u8''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:22:9+59 +function $1_aptos_hash_spec_ripemd160_internal(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_aptos_hash_spec_ripemd160_internal(bytes); +$IsValid'vec'u8''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:27:9+61 +function $1_aptos_hash_spec_blake2b_256_internal(bytes: Vec (int)): Vec (int); +axiom (forall bytes: Vec (int) :: +(var $$res := $1_aptos_hash_spec_blake2b_256_internal(bytes); +$IsValid'vec'u8''($$res))); + +// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/reconfiguration.move:168:5+155 +function {:inline} $1_reconfiguration_$last_reconfiguration_time($1_reconfiguration_Configuration_$memory: $Memory $1_reconfiguration_Configuration): int { + $ResourceValue($1_reconfiguration_Configuration_$memory, 1)->$last_reconfiguration_time +} + +// struct reconfiguration::Configuration at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/reconfiguration.move:43:5+306 +datatype $1_reconfiguration_Configuration { + $1_reconfiguration_Configuration($epoch: int, $last_reconfiguration_time: int, $events: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent') +} +function {:inline} $Update'$1_reconfiguration_Configuration'_epoch(s: $1_reconfiguration_Configuration, x: int): $1_reconfiguration_Configuration { + $1_reconfiguration_Configuration(x, s->$last_reconfiguration_time, s->$events) +} +function {:inline} $Update'$1_reconfiguration_Configuration'_last_reconfiguration_time(s: $1_reconfiguration_Configuration, x: int): $1_reconfiguration_Configuration { + $1_reconfiguration_Configuration(s->$epoch, x, s->$events) +} +function {:inline} $Update'$1_reconfiguration_Configuration'_events(s: $1_reconfiguration_Configuration, x: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'): $1_reconfiguration_Configuration { + $1_reconfiguration_Configuration(s->$epoch, s->$last_reconfiguration_time, x) +} +function $IsValid'$1_reconfiguration_Configuration'(s: $1_reconfiguration_Configuration): bool { + $IsValid'u64'(s->$epoch) + && $IsValid'u64'(s->$last_reconfiguration_time) + && $IsValid'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(s->$events) +} +function {:inline} $IsEqual'$1_reconfiguration_Configuration'(s1: $1_reconfiguration_Configuration, s2: $1_reconfiguration_Configuration): bool { + s1 == s2 +} +var $1_reconfiguration_Configuration_$memory: $Memory $1_reconfiguration_Configuration; + +// struct reconfiguration::NewEpochEvent at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/reconfiguration.move:30:5+64 +datatype $1_reconfiguration_NewEpochEvent { + $1_reconfiguration_NewEpochEvent($epoch: int) +} +function {:inline} $Update'$1_reconfiguration_NewEpochEvent'_epoch(s: $1_reconfiguration_NewEpochEvent, x: int): $1_reconfiguration_NewEpochEvent { + $1_reconfiguration_NewEpochEvent(x) +} +function $IsValid'$1_reconfiguration_NewEpochEvent'(s: $1_reconfiguration_NewEpochEvent): bool { + $IsValid'u64'(s->$epoch) +} +function {:inline} $IsEqual'$1_reconfiguration_NewEpochEvent'(s1: $1_reconfiguration_NewEpochEvent, s2: $1_reconfiguration_NewEpochEvent): bool { + s1 == s2 +} + +// struct timelock::CreateTransaction at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:155:5+189 +datatype $1_timelock_CreateTransaction { + $1_timelock_CreateTransaction($timelock_account: int, $creator: int, $transaction_hash: Vec (int), $transaction: $1_timelock_TimelockTransaction) +} +function {:inline} $Update'$1_timelock_CreateTransaction'_timelock_account(s: $1_timelock_CreateTransaction, x: int): $1_timelock_CreateTransaction { + $1_timelock_CreateTransaction(x, s->$creator, s->$transaction_hash, s->$transaction) +} +function {:inline} $Update'$1_timelock_CreateTransaction'_creator(s: $1_timelock_CreateTransaction, x: int): $1_timelock_CreateTransaction { + $1_timelock_CreateTransaction(s->$timelock_account, x, s->$transaction_hash, s->$transaction) +} +function {:inline} $Update'$1_timelock_CreateTransaction'_transaction_hash(s: $1_timelock_CreateTransaction, x: Vec (int)): $1_timelock_CreateTransaction { + $1_timelock_CreateTransaction(s->$timelock_account, s->$creator, x, s->$transaction) +} +function {:inline} $Update'$1_timelock_CreateTransaction'_transaction(s: $1_timelock_CreateTransaction, x: $1_timelock_TimelockTransaction): $1_timelock_CreateTransaction { + $1_timelock_CreateTransaction(s->$timelock_account, s->$creator, s->$transaction_hash, x) +} +function $IsValid'$1_timelock_CreateTransaction'(s: $1_timelock_CreateTransaction): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'address'(s->$creator) + && $IsValid'vec'u8''(s->$transaction_hash) + && $IsValid'$1_timelock_TimelockTransaction'(s->$transaction) +} +function {:inline} $IsEqual'$1_timelock_CreateTransaction'(s1: $1_timelock_CreateTransaction, s2: $1_timelock_CreateTransaction): bool { + $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) + && $IsEqual'address'(s1->$creator, s2->$creator) + && $IsEqual'vec'u8''(s1->$transaction_hash, s2->$transaction_hash) + && $IsEqual'$1_timelock_TimelockTransaction'(s1->$transaction, s2->$transaction)} + +// struct timelock::AddCreators at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:124:5+118 +datatype $1_timelock_AddCreators { + $1_timelock_AddCreators($timelock_account: int, $creators_added: Vec (int)) +} +function {:inline} $Update'$1_timelock_AddCreators'_timelock_account(s: $1_timelock_AddCreators, x: int): $1_timelock_AddCreators { + $1_timelock_AddCreators(x, s->$creators_added) +} +function {:inline} $Update'$1_timelock_AddCreators'_creators_added(s: $1_timelock_AddCreators, x: Vec (int)): $1_timelock_AddCreators { + $1_timelock_AddCreators(s->$timelock_account, x) +} +function $IsValid'$1_timelock_AddCreators'(s: $1_timelock_AddCreators): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'vec'address''(s->$creators_added) +} +function {:inline} $IsEqual'$1_timelock_AddCreators'(s1: $1_timelock_AddCreators, s2: $1_timelock_AddCreators): bool { + $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) + && $IsEqual'vec'address''(s1->$creators_added, s2->$creators_added)} + +// struct timelock::AddExecutors at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:136:5+120 +datatype $1_timelock_AddExecutors { + $1_timelock_AddExecutors($timelock_account: int, $executors_added: Vec (int)) +} +function {:inline} $Update'$1_timelock_AddExecutors'_timelock_account(s: $1_timelock_AddExecutors, x: int): $1_timelock_AddExecutors { + $1_timelock_AddExecutors(x, s->$executors_added) +} +function {:inline} $Update'$1_timelock_AddExecutors'_executors_added(s: $1_timelock_AddExecutors, x: Vec (int)): $1_timelock_AddExecutors { + $1_timelock_AddExecutors(s->$timelock_account, x) +} +function $IsValid'$1_timelock_AddExecutors'(s: $1_timelock_AddExecutors): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'vec'address''(s->$executors_added) +} +function {:inline} $IsEqual'$1_timelock_AddExecutors'(s1: $1_timelock_AddExecutors, s2: $1_timelock_AddExecutors): bool { + $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) + && $IsEqual'vec'address''(s1->$executors_added, s2->$executors_added)} + +// struct timelock::CancelTransaction at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:163:5+145 +datatype $1_timelock_CancelTransaction { + $1_timelock_CancelTransaction($timelock_account: int, $actor: int, $transaction_hash: Vec (int)) +} +function {:inline} $Update'$1_timelock_CancelTransaction'_timelock_account(s: $1_timelock_CancelTransaction, x: int): $1_timelock_CancelTransaction { + $1_timelock_CancelTransaction(x, s->$actor, s->$transaction_hash) +} +function {:inline} $Update'$1_timelock_CancelTransaction'_actor(s: $1_timelock_CancelTransaction, x: int): $1_timelock_CancelTransaction { + $1_timelock_CancelTransaction(s->$timelock_account, x, s->$transaction_hash) +} +function {:inline} $Update'$1_timelock_CancelTransaction'_transaction_hash(s: $1_timelock_CancelTransaction, x: Vec (int)): $1_timelock_CancelTransaction { + $1_timelock_CancelTransaction(s->$timelock_account, s->$actor, x) +} +function $IsValid'$1_timelock_CancelTransaction'(s: $1_timelock_CancelTransaction): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'address'(s->$actor) + && $IsValid'vec'u8''(s->$transaction_hash) +} +function {:inline} $IsEqual'$1_timelock_CancelTransaction'(s1: $1_timelock_CancelTransaction, s2: $1_timelock_CancelTransaction): bool { + $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) + && $IsEqual'address'(s1->$actor, s2->$actor) + && $IsEqual'vec'u8''(s1->$transaction_hash, s2->$transaction_hash)} + +// struct timelock::RemoveCreators at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:130:5+123 +datatype $1_timelock_RemoveCreators { + $1_timelock_RemoveCreators($timelock_account: int, $creators_removed: Vec (int)) +} +function {:inline} $Update'$1_timelock_RemoveCreators'_timelock_account(s: $1_timelock_RemoveCreators, x: int): $1_timelock_RemoveCreators { + $1_timelock_RemoveCreators(x, s->$creators_removed) +} +function {:inline} $Update'$1_timelock_RemoveCreators'_creators_removed(s: $1_timelock_RemoveCreators, x: Vec (int)): $1_timelock_RemoveCreators { + $1_timelock_RemoveCreators(s->$timelock_account, x) +} +function $IsValid'$1_timelock_RemoveCreators'(s: $1_timelock_RemoveCreators): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'vec'address''(s->$creators_removed) +} +function {:inline} $IsEqual'$1_timelock_RemoveCreators'(s1: $1_timelock_RemoveCreators, s2: $1_timelock_RemoveCreators): bool { + $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) + && $IsEqual'vec'address''(s1->$creators_removed, s2->$creators_removed)} + +// struct timelock::RemoveExecutors at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:142:5+125 +datatype $1_timelock_RemoveExecutors { + $1_timelock_RemoveExecutors($timelock_account: int, $executors_removed: Vec (int)) +} +function {:inline} $Update'$1_timelock_RemoveExecutors'_timelock_account(s: $1_timelock_RemoveExecutors, x: int): $1_timelock_RemoveExecutors { + $1_timelock_RemoveExecutors(x, s->$executors_removed) +} +function {:inline} $Update'$1_timelock_RemoveExecutors'_executors_removed(s: $1_timelock_RemoveExecutors, x: Vec (int)): $1_timelock_RemoveExecutors { + $1_timelock_RemoveExecutors(s->$timelock_account, x) +} +function $IsValid'$1_timelock_RemoveExecutors'(s: $1_timelock_RemoveExecutors): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'vec'address''(s->$executors_removed) +} +function {:inline} $IsEqual'$1_timelock_RemoveExecutors'(s1: $1_timelock_RemoveExecutors, s2: $1_timelock_RemoveExecutors): bool { + $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) + && $IsEqual'vec'address''(s1->$executors_removed, s2->$executors_removed)} + +// struct timelock::TimelockAccount at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:88:5+784 +datatype $1_timelock_TimelockAccount { + $1_timelock_TimelockAccount($creators: Vec (int), $executors: Vec (int), $min_num_seconds_execute: int, $transactions: Table int ($1_timelock_TimelockTransaction), $signer_cap: $1_account_SignerCapability) +} +function {:inline} $Update'$1_timelock_TimelockAccount'_creators(s: $1_timelock_TimelockAccount, x: Vec (int)): $1_timelock_TimelockAccount { + $1_timelock_TimelockAccount(x, s->$executors, s->$min_num_seconds_execute, s->$transactions, s->$signer_cap) +} +function {:inline} $Update'$1_timelock_TimelockAccount'_executors(s: $1_timelock_TimelockAccount, x: Vec (int)): $1_timelock_TimelockAccount { + $1_timelock_TimelockAccount(s->$creators, x, s->$min_num_seconds_execute, s->$transactions, s->$signer_cap) +} +function {:inline} $Update'$1_timelock_TimelockAccount'_min_num_seconds_execute(s: $1_timelock_TimelockAccount, x: int): $1_timelock_TimelockAccount { + $1_timelock_TimelockAccount(s->$creators, s->$executors, x, s->$transactions, s->$signer_cap) +} +function {:inline} $Update'$1_timelock_TimelockAccount'_transactions(s: $1_timelock_TimelockAccount, x: Table int ($1_timelock_TimelockTransaction)): $1_timelock_TimelockAccount { + $1_timelock_TimelockAccount(s->$creators, s->$executors, s->$min_num_seconds_execute, x, s->$signer_cap) +} +function {:inline} $Update'$1_timelock_TimelockAccount'_signer_cap(s: $1_timelock_TimelockAccount, x: $1_account_SignerCapability): $1_timelock_TimelockAccount { + $1_timelock_TimelockAccount(s->$creators, s->$executors, s->$min_num_seconds_execute, s->$transactions, x) +} +function $IsValid'$1_timelock_TimelockAccount'(s: $1_timelock_TimelockAccount): bool { + $IsValid'vec'address''(s->$creators) + && $IsValid'vec'address''(s->$executors) + && $IsValid'u64'(s->$min_num_seconds_execute) + && $IsValid'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(s->$transactions) + && $IsValid'$1_account_SignerCapability'(s->$signer_cap) +} +function {:inline} $IsEqual'$1_timelock_TimelockAccount'(s1: $1_timelock_TimelockAccount, s2: $1_timelock_TimelockAccount): bool { + $IsEqual'vec'address''(s1->$creators, s2->$creators) + && $IsEqual'vec'address''(s1->$executors, s2->$executors) + && $IsEqual'u64'(s1->$min_num_seconds_execute, s2->$min_num_seconds_execute) + && $IsEqual'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(s1->$transactions, s2->$transactions) + && $IsEqual'$1_account_SignerCapability'(s1->$signer_cap, s2->$signer_cap)} +var $1_timelock_TimelockAccount_$memory: $Memory $1_timelock_TimelockAccount; + +// struct timelock::TimelockTransaction at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:107:5+631 +datatype $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction($execution_hash: Vec (int), $creator: int, $creation_time_secs: int, $num_seconds_execute: int, $salt: Vec (int), $executed: bool) +} +function {:inline} $Update'$1_timelock_TimelockTransaction'_execution_hash(s: $1_timelock_TimelockTransaction, x: Vec (int)): $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction(x, s->$creator, s->$creation_time_secs, s->$num_seconds_execute, s->$salt, s->$executed) +} +function {:inline} $Update'$1_timelock_TimelockTransaction'_creator(s: $1_timelock_TimelockTransaction, x: int): $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction(s->$execution_hash, x, s->$creation_time_secs, s->$num_seconds_execute, s->$salt, s->$executed) +} +function {:inline} $Update'$1_timelock_TimelockTransaction'_creation_time_secs(s: $1_timelock_TimelockTransaction, x: int): $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, x, s->$num_seconds_execute, s->$salt, s->$executed) +} +function {:inline} $Update'$1_timelock_TimelockTransaction'_num_seconds_execute(s: $1_timelock_TimelockTransaction, x: int): $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, s->$creation_time_secs, x, s->$salt, s->$executed) +} +function {:inline} $Update'$1_timelock_TimelockTransaction'_salt(s: $1_timelock_TimelockTransaction, x: Vec (int)): $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, s->$creation_time_secs, s->$num_seconds_execute, x, s->$executed) +} +function {:inline} $Update'$1_timelock_TimelockTransaction'_executed(s: $1_timelock_TimelockTransaction, x: bool): $1_timelock_TimelockTransaction { + $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, s->$creation_time_secs, s->$num_seconds_execute, s->$salt, x) +} +function $IsValid'$1_timelock_TimelockTransaction'(s: $1_timelock_TimelockTransaction): bool { + $IsValid'vec'u8''(s->$execution_hash) + && $IsValid'address'(s->$creator) + && $IsValid'u64'(s->$creation_time_secs) + && $IsValid'u64'(s->$num_seconds_execute) + && $IsValid'vec'u8''(s->$salt) + && $IsValid'bool'(s->$executed) +} +function {:inline} $IsEqual'$1_timelock_TimelockTransaction'(s1: $1_timelock_TimelockTransaction, s2: $1_timelock_TimelockTransaction): bool { + $IsEqual'vec'u8''(s1->$execution_hash, s2->$execution_hash) + && $IsEqual'address'(s1->$creator, s2->$creator) + && $IsEqual'u64'(s1->$creation_time_secs, s2->$creation_time_secs) + && $IsEqual'u64'(s1->$num_seconds_execute, s2->$num_seconds_execute) + && $IsEqual'vec'u8''(s1->$salt, s2->$salt) + && $IsEqual'bool'(s1->$executed, s2->$executed)} + +// struct timelock::UpdateMinNumSecondsExecute at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:148:5+176 +datatype $1_timelock_UpdateMinNumSecondsExecute { + $1_timelock_UpdateMinNumSecondsExecute($timelock_account: int, $old_min_num_seconds_execute: int, $new_min_num_seconds_execute: int) +} +function {:inline} $Update'$1_timelock_UpdateMinNumSecondsExecute'_timelock_account(s: $1_timelock_UpdateMinNumSecondsExecute, x: int): $1_timelock_UpdateMinNumSecondsExecute { + $1_timelock_UpdateMinNumSecondsExecute(x, s->$old_min_num_seconds_execute, s->$new_min_num_seconds_execute) +} +function {:inline} $Update'$1_timelock_UpdateMinNumSecondsExecute'_old_min_num_seconds_execute(s: $1_timelock_UpdateMinNumSecondsExecute, x: int): $1_timelock_UpdateMinNumSecondsExecute { + $1_timelock_UpdateMinNumSecondsExecute(s->$timelock_account, x, s->$new_min_num_seconds_execute) +} +function {:inline} $Update'$1_timelock_UpdateMinNumSecondsExecute'_new_min_num_seconds_execute(s: $1_timelock_UpdateMinNumSecondsExecute, x: int): $1_timelock_UpdateMinNumSecondsExecute { + $1_timelock_UpdateMinNumSecondsExecute(s->$timelock_account, s->$old_min_num_seconds_execute, x) +} +function $IsValid'$1_timelock_UpdateMinNumSecondsExecute'(s: $1_timelock_UpdateMinNumSecondsExecute): bool { + $IsValid'address'(s->$timelock_account) + && $IsValid'u64'(s->$old_min_num_seconds_execute) + && $IsValid'u64'(s->$new_min_num_seconds_execute) +} +function {:inline} $IsEqual'$1_timelock_UpdateMinNumSecondsExecute'(s1: $1_timelock_UpdateMinNumSecondsExecute, s2: $1_timelock_UpdateMinNumSecondsExecute): bool { + s1 == s2 +} + +// fun timelock::get_transaction_hash [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:5+196 +procedure {:inline 1} $1_timelock_get_transaction_hash(_$t0: Vec (int), _$t1: Vec (int)) returns ($ret0: Vec (int)) +{ + // declare local variables + var $t2: Vec (int); + var $t3: $Mutation (Vec (int)); + var $t4: int; + var $t5: Vec (int); + var $t6: Vec (int); + var $t0: Vec (int); + var $t1: Vec (int); + var $temp_0'vec'u8'': Vec (int); + $t0 := _$t0; + $t1 := _$t1; + + // bytecode translation starts here + // trace_local[execution_hash]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:5+1 + assume {:print "$at(2,11385,11386)"} true; + assume {:print "$track_local(102,0,0):", $t0} $t0 == $t0; + + // trace_local[salt]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:5+1 + assume {:print "$track_local(102,0,1):", $t1} $t1 == $t1; + + // $t2 := $t0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:257:21+19 + assume {:print "$at(2,11497,11516)"} true; + $t2 := $t0; + + // trace_local[bytes]($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:257:21+19 + assume {:print "$track_local(102,0,2):", $t2} $t2 == $t2; + + // $t3 := borrow_local($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 + assume {:print "$at(2,11526,11549)"} true; + $t3 := $Mutation($Local(2), EmptyVec(), $t2); + + // vector::append($t3, $t1) on_abort goto L2 with $t4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 + call $t3 := $1_vector_append'u8'($t3, $t1); + if ($abort_flag) { + assume {:print "$at(2,11526,11549)"} true; + $t4 := $abort_code; + assume {:print "$track_abort(102,0):", $t4} $t4 == $t4; + goto L2; + } + + // write_back[LocalRoot($t2)@]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 + $t2 := $Dereference($t3); + + // trace_local[bytes]($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 + assume {:print "$track_local(102,0,2):", $t2} $t2 == $t2; + + // $t5 := move($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 + assume {:print "$at(2,11559,11575)"} true; + $t5 := $t2; + + // $t6 := opaque begin: aptos_hash::keccak256($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 + + // assume WellFormed($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 + assume $IsValid'vec'u8''($t6); + + // assume Eq>($t6, aptos_hash::spec_keccak256($t5)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 + assume $IsEqual'vec'u8''($t6, $1_aptos_hash_spec_keccak256($t5)); + + // $t6 := opaque end: aptos_hash::keccak256($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 + + // trace_return[0]($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:95+106 + assume {:print "$at(2,11475,11581)"} true; + assume {:print "$track_return(102,0,0):", $t6} $t6 == $t6; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 + assume {:print "$at(2,11580,11581)"} true; +L1: + + // return $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 + assume {:print "$at(2,11580,11581)"} true; + $ret0 := $t6; + return; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 +L2: + + // abort($t4) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 + assume {:print "$at(2,11580,11581)"} true; + $abort_code := $t4; + $abort_flag := true; + return; + +} + +// fun timelock::create_timelock_account_seed [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:571:5+210 +procedure {:inline 1} $1_timelock_create_timelock_account_seed(_$t0: Vec (int)) returns ($ret0: Vec (int)) +{ + // declare local variables + var $t1: Vec (int); + var $t2: int; + var $t3: $Mutation (Vec (int)); + var $t4: Vec (int); + var $t5: $Mutation (Vec (int)); + var $t6: Vec (int); + var $t0: Vec (int); + var $temp_0'vec'u8'': Vec (int); + $t0 := _$t0; + + // bytecode translation starts here + // trace_local[seed]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:571:5+1 + assume {:print "$at(2,26195,26196)"} true; + assume {:print "$track_local(102,14,0):", $t0} $t0 == $t0; + + // $t1 := vector::empty() on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:572:28+6 + assume {:print "$at(2,26287,26293)"} true; + call $t1 := $1_vector_empty'u8'(); + if ($abort_flag) { + assume {:print "$at(2,26287,26293)"} true; + $t2 := $abort_code; + assume {:print "$track_abort(102,14):", $t2} $t2 == $t2; + goto L2; + } + + // trace_local[account_seed]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:572:28+6 + assume {:print "$track_local(102,14,1):", $t1} $t1 == $t1; + + // $t3 := borrow_local($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 + assume {:print "$at(2,26305,26342)"} true; + $t3 := $Mutation($Local(1), EmptyVec(), $t1); + + // $t4 := [97, 112, 116, 111, 115, 95, 102, 114, 97, 109, 101, 119, 111, 114, 107, 58, 58, 116, 105, 109, 101, 108, 111, 99, 107] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:29+16 + $t4 := ConcatVec(ConcatVec(ConcatVec(ConcatVec(ConcatVec(ConcatVec(MakeVec4(97, 112, 116, 111), MakeVec4(115, 95, 102, 114)), MakeVec4(97, 109, 101, 119)), MakeVec4(111, 114, 107, 58)), MakeVec4(58, 116, 105, 109)), MakeVec4(101, 108, 111, 99)), MakeVec1(107)); + assume $IsValid'vec'u8''($t4); + + // vector::append($t3, $t4) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 + call $t3 := $1_vector_append'u8'($t3, $t4); + if ($abort_flag) { + assume {:print "$at(2,26305,26342)"} true; + $t2 := $abort_code; + assume {:print "$track_abort(102,14):", $t2} $t2 == $t2; + goto L2; + } + + // write_back[LocalRoot($t1)@]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 + $t1 := $Dereference($t3); + + // trace_local[account_seed]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 + assume {:print "$track_local(102,14,1):", $t1} $t1 == $t1; + + // $t5 := borrow_local($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 + assume {:print "$at(2,26352,26377)"} true; + $t5 := $Mutation($Local(1), EmptyVec(), $t1); + + // vector::append($t5, $t0) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 + call $t5 := $1_vector_append'u8'($t5, $t0); + if ($abort_flag) { + assume {:print "$at(2,26352,26377)"} true; + $t2 := $abort_code; + assume {:print "$track_abort(102,14):", $t2} $t2 == $t2; + goto L2; + } + + // write_back[LocalRoot($t1)@]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 + $t1 := $Dereference($t5); + + // trace_local[account_seed]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 + assume {:print "$track_local(102,14,1):", $t1} $t1 == $t1; + + // $t6 := move($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:575:9+12 + assume {:print "$at(2,26387,26399)"} true; + $t6 := $t1; + + // trace_return[0]($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:571:68+147 + assume {:print "$at(2,26258,26405)"} true; + assume {:print "$track_return(102,14,0):", $t6} $t6 == $t6; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 + assume {:print "$at(2,26404,26405)"} true; +L1: + + // return $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 + assume {:print "$at(2,26404,26405)"} true; + $ret0 := $t6; + return; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 +L2: + + // abort($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 + assume {:print "$at(2,26404,26405)"} true; + $abort_code := $t2; + $abort_flag := true; + return; + +} + +// fun timelock::is_creator [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:199:5+184 +procedure {:inline 1} $1_timelock_is_creator(_$t0: int, _$t1: int) returns ($ret0: bool) +{ + // declare local variables + var $t2: $1_timelock_TimelockAccount; + var $t3: int; + var $t4: Vec (int); + var $t5: bool; + var $t0: int; + var $t1: int; + var $temp_0'address': int; + var $temp_0'bool': bool; + $t0 := _$t0; + $t1 := _$t1; + + // bytecode translation starts here + // trace_local[addr]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:199:5+1 + assume {:print "$at(2,8797,8798)"} true; + assume {:print "$track_local(102,16,0):", $t0} $t0 == $t0; + + // trace_local[timelock_account]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:199:5+1 + assume {:print "$track_local(102,16,1):", $t1} $t1 == $t1; + + // $t2 := get_global<0x1::timelock::TimelockAccount>($t1) on_abort goto L2 with $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+48 + assume {:print "$at(2,8902,8950)"} true; + if (!$ResourceExists($1_timelock_TimelockAccount_$memory, $t1)) { + call $ExecFailureAbort(); + } else { + $t2 := $ResourceValue($1_timelock_TimelockAccount_$memory, $t1); + } + if ($abort_flag) { + assume {:print "$at(2,8902,8950)"} true; + $t3 := $abort_code; + assume {:print "$track_abort(102,16):", $t3} $t3 == $t3; + goto L2; + } + + // $t4 := get_field<0x1::timelock::TimelockAccount>.creators($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+73 + $t4 := $t2->$creators; + + // $t5 := vector::contains
($t4, $t0) on_abort goto L2 with $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+73 + call $t5 := $1_vector_contains'address'($t4, $t0); + if ($abort_flag) { + assume {:print "$at(2,8902,8975)"} true; + $t3 := $abort_code; + assume {:print "$track_abort(102,16):", $t3} $t3 == $t3; + goto L2; + } + + // trace_return[0]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+73 + assume {:print "$track_return(102,16,0):", $t5} $t5 == $t5; + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 + assume {:print "$at(2,8980,8981)"} true; +L1: + + // return $t5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 + assume {:print "$at(2,8980,8981)"} true; + $ret0 := $t5; + return; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 +L2: + + // abort($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 + assume {:print "$at(2,8980,8981)"} true; + $abort_code := $t3; + $abort_flag := true; + return; + +} + +// fun timelock::is_executor [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:206:5+341 +procedure {:inline 1} $1_timelock_is_executor(_$t0: int, _$t1: int) returns ($ret0: bool) +{ + // declare local variables + var $t2: $1_timelock_TimelockAccount; + var $t3: bool; + var $t4: $1_timelock_TimelockAccount; + var $t5: $1_timelock_TimelockAccount; + var $t6: int; + var $t7: Vec (int); + var $t8: bool; + var $t9: Vec (int); + var $t10: bool; + var $t11: Vec (int); + var $t12: bool; + var $t0: int; + var $t1: int; + var $temp_0'$1_timelock_TimelockAccount': $1_timelock_TimelockAccount; + var $temp_0'address': int; + var $temp_0'bool': bool; + $t0 := _$t0; + $t1 := _$t1; + + // bytecode translation starts here + // assume Identical($t4, global<0x1::timelock::TimelockAccount>($t1)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.spec.move:128:9+57 + assume {:print "$at(3,8349,8406)"} true; + assume ($t4 == $ResourceValue($1_timelock_TimelockAccount_$memory, $t1)); + + // trace_local[addr]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:206:5+1 + assume {:print "$at(2,9159,9160)"} true; + assume {:print "$track_local(102,17,0):", $t0} $t0 == $t0; + + // trace_local[timelock_account]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:206:5+1 + assume {:print "$track_local(102,17,1):", $t1} $t1 == $t1; + + // $t5 := get_global<0x1::timelock::TimelockAccount>($t1) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:207:24+48 + assume {:print "$at(2,9280,9328)"} true; + if (!$ResourceExists($1_timelock_TimelockAccount_$memory, $t1)) { + call $ExecFailureAbort(); + } else { + $t5 := $ResourceValue($1_timelock_TimelockAccount_$memory, $t1); + } + if ($abort_flag) { + assume {:print "$at(2,9280,9328)"} true; + $t6 := $abort_code; + assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; + goto L4; + } + + // trace_local[timelock]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:207:24+48 + assume {:print "$track_local(102,17,2):", $t5} $t5 == $t5; + + // $t7 := get_field<0x1::timelock::TimelockAccount>.executors($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:13+29 + assume {:print "$at(2,9342,9371)"} true; + $t7 := $t5->$executors; + + // $t8 := vector::is_empty
($t7) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:13+29 + call $t8 := $1_vector_is_empty'address'($t7); + if ($abort_flag) { + assume {:print "$at(2,9342,9371)"} true; + $t6 := $abort_code; + assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; + goto L4; + } + + // if ($t8) goto L1 else goto L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 + if ($t8) { goto L1; } else { goto L0; } + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 + assume {:print "$at(2,9387,9420)"} true; +L1: + + // $t9 := get_field<0x1::timelock::TimelockAccount>.creators($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 + assume {:print "$at(2,9387,9420)"} true; + $t9 := $t5->$creators; + + // $t10 := vector::contains
($t9, $t0) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 + call $t10 := $1_vector_contains'address'($t9, $t0); + if ($abort_flag) { + assume {:print "$at(2,9387,9420)"} true; + $t6 := $abort_code; + assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; + goto L4; + } + + // $t3 := $t10 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 + $t3 := $t10; + + // trace_local[$t4]($t10) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 + assume {:print "$track_local(102,17,3):", $t10} $t10 == $t10; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 + assume {:print "$at(2,9338,9494)"} true; +L2: + + // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 + assume {:print "$at(2,9338,9494)"} true; + assume {:print "$track_return(102,17,0):", $t3} $t3 == $t3; + + // goto L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 + goto L3; + + // label L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 + assume {:print "$at(2,9450,9484)"} true; +L0: + + // $t11 := get_field<0x1::timelock::TimelockAccount>.executors($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 + assume {:print "$at(2,9450,9484)"} true; + $t11 := $t5->$executors; + + // $t12 := vector::contains
($t11, $t0) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 + call $t12 := $1_vector_contains'address'($t11, $t0); + if ($abort_flag) { + assume {:print "$at(2,9450,9484)"} true; + $t6 := $abort_code; + assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; + goto L4; + } + + // $t3 := $t12 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 + $t3 := $t12; + + // trace_local[$t4]($t12) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 + assume {:print "$track_local(102,17,3):", $t12} $t12 == $t12; + + // goto L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 + goto L2; + + // label L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 + assume {:print "$at(2,9499,9500)"} true; +L3: + + // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 + assume {:print "$at(2,9499,9500)"} true; + $ret0 := $t3; + return; + + // label L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 +L4: + + // abort($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 + assume {:print "$at(2,9499,9500)"} true; + $abort_code := $t6; + $abort_flag := true; + return; + +} + +// fun timelock::validate_members [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1008 +procedure {:inline 1} $1_timelock_validate_members(_$t0: Vec (int), _$t1: int, _$t2: int) returns () +{ + // declare local variables + var $t3: Vec (int); + var $t4: int; + var $t5: int; + var $t6: int; + var $t7: int; + var $t8: int; + var $t9: int; + var $t10: bool; + var $t11: int; + var $t12: bool; + var $t13: Vec (int); + var $t14: bool; + var $t15: int; + var $t16: int; + var $t17: int; + var $t18: $Mutation (Vec (int)); + var $t19: int; + var $t20: int; + var $t21: int; + var $t0: Vec (int); + var $t1: int; + var $t2: int; + var $temp_0'address': int; + var $temp_0'u64': int; + var $temp_0'vec'address'': Vec (int); + $t0 := _$t0; + $t1 := _$t1; + $t2 := _$t2; + + // bytecode translation starts here + // trace_local[members]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1 + assume {:print "$at(2,26666,26667)"} true; + assume {:print "$track_local(102,21,0):", $t0} $t0 == $t0; + + // trace_local[timelock_address]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1 + assume {:print "$track_local(102,21,1):", $t1} $t1 == $t1; + + // trace_local[duplicate_error]($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1 + assume {:print "$track_local(102,21,2):", $t2} $t2 == $t2; + + // $t3 := vector::empty
() on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:582:41+6 + assume {:print "$at(2,26805,26811)"} true; + call $t3 := $1_vector_empty'address'(); + if ($abort_flag) { + assume {:print "$at(2,26805,26811)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // trace_local[distinct]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:582:41+6 + assume {:print "$track_local(102,21,3):", $t3} $t3 == $t3; + + // $t8 := vector::length
($t0) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:583:21+16 + assume {:print "$at(2,26835,26851)"} true; + call $t8 := $1_vector_length'address'($t0); + if ($abort_flag) { + assume {:print "$at(2,26835,26851)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // trace_local[total]($t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:583:21+16 + assume {:print "$track_local(102,21,4):", $t8} $t8 == $t8; + + // $t9 := 0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:584:17+1 + assume {:print "$at(2,26869,26870)"} true; + $t9 := 0; + assume $IsValid'u64'($t9); + + // trace_local[i]($t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:584:17+1 + assume {:print "$track_local(102,21,5):", $t9} $t9 == $t9; + + // label L6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:586:13+339 + assume {:print "$at(2,26901,27240)"} true; +L6: + + // assert Le($t9, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:587:17+21 + assume {:print "$at(2,26924,26945)"} true; + assert {:msg "assert_failed(2,26924,26945): base case of the loop invariant does not hold"} + ($t9 <= $t8); + + // assert Eq(Len
($t3), $t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:588:17+29 + assume {:print "$at(2,26962,26991)"} true; + assert {:msg "assert_failed(2,26962,26991): base case of the loop invariant does not hold"} + $IsEqual'num'(LenVec($t3), $t9); + + // assert forall k: num: Range(0, $t9): Eq
(Index($t3, k), Index($t0, k)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:589:17+54 + assume {:print "$at(2,27008,27062)"} true; + assert {:msg "assert_failed(2,27008,27062): base case of the loop invariant does not hold"} + (var $range_0 := $Range(0, $t9); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + ($IsEqual'address'(ReadVec($t3, k), ReadVec($t0, k)))))); + + // assert forall k: num: Range(0, $t9): Neq
(Index($t0, k), $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:590:17+59 + assume {:print "$at(2,27079,27138)"} true; + assert {:msg "assert_failed(2,27079,27138): base case of the loop invariant does not hold"} + (var $range_0 := $Range(0, $t9); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + (!$IsEqual'address'(ReadVec($t0, k), $t1))))); + + // assert forall k: num: Range(0, $t9): forall l: num: Range(0, k): Neq
(Index($t0, k), Index($t0, l)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume {:print "$at(2,27155,27226)"} true; + assert {:msg "assert_failed(2,27155,27226): base case of the loop invariant does not hold"} + (var $range_0 := $Range(0, $t9); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + ((var $range_2 := $Range(0, k); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var l := $i_3; + (!$IsEqual'address'(ReadVec($t0, k), ReadVec($t0, l)))))))))); + + // $t3 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t3; + + // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'vec'address''($t3); + + // $t5 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t5; + + // assume WellFormed($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'u64'($t5); + + // $t10 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t10; + + // assume WellFormed($t10) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'bool'($t10); + + // $t11 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t11; + + // assume WellFormed($t11) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'address'($t11); + + // $t12 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t12; + + // assume WellFormed($t12) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'bool'($t12); + + // $t13 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t13; + + // assume WellFormed($t13) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'vec'address''($t13); + + // $t14 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t14; + + // assume WellFormed($t14) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'bool'($t14); + + // $t15 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t15; + + // assume WellFormed($t15) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'u64'($t15); + + // $t16 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t16; + + // assume WellFormed($t16) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'u64'($t16); + + // $t17 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t17; + + // assume WellFormed($t17) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'u64'($t17); + + // $t18 := havoc[mut_all]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + havoc $t18; + + // assume WellFormed($t18) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume $IsValid'vec'address''($Dereference($t18)); + + // trace_local[distinct]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume {:print "$info(): enter loop, variable(s) distinct, i havocked and reassigned"} true; + assume {:print "$track_local(102,21,3):", $t3} $t3 == $t3; + + // trace_local[i]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume {:print "$track_local(102,21,5):", $t5} $t5 == $t5; + + // assume Not(AbortFlag()) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume {:print "$info(): loop invariant holds at current state"} true; + assume !$abort_flag; + + // assume Le($t5, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:587:17+21 + assume {:print "$at(2,26924,26945)"} true; + assume ($t5 <= $t8); + + // assume Eq(Len
($t3), $t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:588:17+29 + assume {:print "$at(2,26962,26991)"} true; + assume $IsEqual'num'(LenVec($t3), $t5); + + // assume forall k: num: Range(0, $t5): Eq
(Index($t3, k), Index($t0, k)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:589:17+54 + assume {:print "$at(2,27008,27062)"} true; + assume (var $range_0 := $Range(0, $t5); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + ($IsEqual'address'(ReadVec($t3, k), ReadVec($t0, k)))))); + + // assume forall k: num: Range(0, $t5): Neq
(Index($t0, k), $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:590:17+59 + assume {:print "$at(2,27079,27138)"} true; + assume (var $range_0 := $Range(0, $t5); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + (!$IsEqual'address'(ReadVec($t0, k), $t1))))); + + // assume forall k: num: Range(0, $t5): forall l: num: Range(0, k): Neq
(Index($t0, k), Index($t0, l)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume {:print "$at(2,27155,27226)"} true; + assume (var $range_0 := $Range(0, $t5); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + ((var $range_2 := $Range(0, k); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var l := $i_3; + (!$IsEqual'address'(ReadVec($t0, k), ReadVec($t0, l)))))))))); + + // $t10 := <($t5, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:593:13+9 + assume {:print "$at(2,27254,27263)"} true; + call $t10 := $Lt($t5, $t8); + + // if ($t10) goto L1 else goto L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 + assume {:print "$at(2,26880,27667)"} true; + if ($t10) { goto L1; } else { goto L0; } + + // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:595:27+7 + assume {:print "$at(2,27303,27310)"} true; +L1: + + // $t11 := vector::borrow
($t0, $t5) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:595:27+17 + assume {:print "$at(2,27303,27320)"} true; + call $t11 := $1_vector_borrow'address'($t0, $t5); + if ($abort_flag) { + assume {:print "$at(2,27303,27320)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // trace_local[member]($t11) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:595:26+18 + assume {:print "$track_local(102,21,6):", $t11} $t11 == $t11; + + // $t12 := !=($t11, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:597:17+26 + assume {:print "$at(2,27359,27385)"} true; + $t12 := !$IsEqual'address'($t11, $t1); + + // if ($t12) goto L3 else goto L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 + assume {:print "$at(2,27334,27340)"} true; + if ($t12) { goto L3; } else { goto L2; } + + // label L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 + assume {:print "$at(2,27496,27522)"} true; +L3: + + // $t13 := copy($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 + assume {:print "$at(2,27496,27522)"} true; + $t13 := $t3; + + // ($t14, $t15) := vector::index_of
($t13, $t11) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 + call $t14,$t15 := $1_vector_index_of'address'($t13, $t11); + if ($abort_flag) { + assume {:print "$at(2,27496,27522)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // drop($t15) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 + + // if ($t14) goto L4 else goto L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:21+6 + assume {:print "$at(2,27544,27550)"} true; + if ($t14) { goto L4; } else { goto L5; } + + // label L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 + assume {:print "$at(2,27607,27633)"} true; +L5: + + // $t18 := borrow_local($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 + assume {:print "$at(2,27607,27633)"} true; + $t18 := $Mutation($Local(3), EmptyVec(), $t3); + + // vector::push_back
($t18, $t11) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 + call $t18 := $1_vector_push_back'address'($t18, $t11); + if ($abort_flag) { + assume {:print "$at(2,27607,27633)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // write_back[LocalRoot($t3)@]($t18) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 + $t3 := $Dereference($t18); + + // trace_local[distinct]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 + assume {:print "$track_local(102,21,3):", $t3} $t3 == $t3; + + // $t16 := 1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:603:21+1 + assume {:print "$at(2,27655,27656)"} true; + $t16 := 1; + assume $IsValid'u64'($t16); + + // $t17 := +($t5, $t16) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:603:17+5 + call $t17 := $AddU64($t5, $t16); + if ($abort_flag) { + assume {:print "$at(2,27651,27656)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // trace_local[i]($t17) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:603:13+9 + assume {:print "$track_local(102,21,5):", $t17} $t17 == $t17; + + // goto L7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 + assume {:print "$at(2,26880,27667)"} true; + goto L7; + + // label L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 + assume {:print "$at(2,27536,27542)"} true; +L4: + + // $t19 := error::invalid_argument($t2) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:29+40 + assume {:print "$at(2,27552,27592)"} true; + call $t19 := $1_error_invalid_argument($t2); + if ($abort_flag) { + assume {:print "$at(2,27552,27592)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // trace_abort($t19) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 + assume {:print "$at(2,27536,27542)"} true; + assume {:print "$track_abort(102,21):", $t19} $t19 == $t19; + + // $t7 := move($t19) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 + $t7 := $t19; + + // goto L9 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 + goto L9; + + // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 + assume {:print "$at(2,27334,27340)"} true; +L2: + + // $t20 := 10 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:598:41+22 + assume {:print "$at(2,27427,27449)"} true; + $t20 := 10; + assume $IsValid'u64'($t20); + + // $t21 := error::invalid_argument($t20) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:598:17+47 + call $t21 := $1_error_invalid_argument($t20); + if ($abort_flag) { + assume {:print "$at(2,27403,27450)"} true; + $t7 := $abort_code; + assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; + goto L9; + } + + // trace_abort($t21) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 + assume {:print "$at(2,27334,27340)"} true; + assume {:print "$track_abort(102,21):", $t21} $t21 == $t21; + + // $t7 := move($t21) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 + $t7 := $t21; + + // goto L9 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 + goto L9; + + // label L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 + assume {:print "$at(2,26880,27667)"} true; +L0: + + // goto L8 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:102+911 + assume {:print "$at(2,26763,27674)"} true; + goto L8; + + // label L7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 + // Loop invariant checking block for the loop started with header: L6 + assume {:print "$at(2,26880,27667)"} true; +L7: + + // assert Le($t17, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:587:17+21 + assume {:print "$at(2,26924,26945)"} true; + assert {:msg "assert_failed(2,26924,26945): induction case of the loop invariant does not hold"} + ($t17 <= $t8); + + // assert Eq(Len
($t3), $t17) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:588:17+29 + assume {:print "$at(2,26962,26991)"} true; + assert {:msg "assert_failed(2,26962,26991): induction case of the loop invariant does not hold"} + $IsEqual'num'(LenVec($t3), $t17); + + // assert forall k: num: Range(0, $t17): Eq
(Index($t3, k), Index($t0, k)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:589:17+54 + assume {:print "$at(2,27008,27062)"} true; + assert {:msg "assert_failed(2,27008,27062): induction case of the loop invariant does not hold"} + (var $range_0 := $Range(0, $t17); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + ($IsEqual'address'(ReadVec($t3, k), ReadVec($t0, k)))))); + + // assert forall k: num: Range(0, $t17): Neq
(Index($t0, k), $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:590:17+59 + assume {:print "$at(2,27079,27138)"} true; + assert {:msg "assert_failed(2,27079,27138): induction case of the loop invariant does not hold"} + (var $range_0 := $Range(0, $t17); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + (!$IsEqual'address'(ReadVec($t0, k), $t1))))); + + // assert forall k: num: Range(0, $t17): forall l: num: Range(0, k): Neq
(Index($t0, k), Index($t0, l)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume {:print "$at(2,27155,27226)"} true; + assert {:msg "assert_failed(2,27155,27226): induction case of the loop invariant does not hold"} + (var $range_0 := $Range(0, $t17); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; + ((var $range_2 := $Range(0, k); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var l := $i_3; + (!$IsEqual'address'(ReadVec($t0, k), ReadVec($t0, l)))))))))); + + // stop() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 + assume false; + return; + + // label L8 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 + assume {:print "$at(2,27673,27674)"} true; +L8: + + // return () at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 + assume {:print "$at(2,27673,27674)"} true; + return; + + // label L9 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 +L9: + + // abort($t7) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 + assume {:print "$at(2,27673,27674)"} true; + $abort_code := $t7; + $abort_flag := true; + return; + +} diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/ast.rs index 34e84c50ce1..68fbad94f3e 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/ast.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/ast.rs @@ -45,14 +45,28 @@ pub enum AttributeValue_ { Value(Value), Module(ModuleIdent), ModuleAccess(ModuleAccess), + List(Vec), + Range { + lo: Box, + hi: Box, + inclusive_hi: bool, + }, + Union(Vec), } pub type AttributeValue = Spanned; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConstraintOp { + Ne, + In, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum Attribute_ { Name(Name), Assigned(Name, Box), Parameterized(Name, Attributes), + Constrained(Name, ConstraintOp, Box), } pub type Attribute = Spanned; @@ -61,7 +75,8 @@ impl Attribute_ { match self { Attribute_::Name(nm) | Attribute_::Assigned(nm, _) - | Attribute_::Parameterized(nm, _) => nm, + | Attribute_::Parameterized(nm, _) + | Attribute_::Constrained(nm, _, _) => nm, } } } @@ -70,6 +85,11 @@ impl Attribute_ { pub enum AttributeName_ { Unknown(Symbol), Known(KnownAttribute), + /// Unique-by-construction key used by `Attribute_::Constrained` entries. + /// `slot` makes duplicate constraints on the same parameter (e.g. + /// `a in X, a != Y`) distinct in the [`UniqueMap`] that stores attributes, + /// while [`Display`](std::fmt::Display) still shows the underlying name. + Disambiguated(Symbol, u32), } pub type AttributeName = Spanned; @@ -880,6 +900,7 @@ impl fmt::Display for AttributeName_ { match self { AttributeName_::Unknown(sym) => write!(f, "{}", sym), AttributeName_::Known(known) => write!(f, "{}", known.name()), + AttributeName_::Disambiguated(sym, _) => write!(f, "{}", sym), } } } @@ -990,6 +1011,29 @@ impl AstDebug for AttributeValue_ { AttributeValue_::Value(v) => v.ast_debug(w), AttributeValue_::Module(m) => w.write(&format!("{}", m)), AttributeValue_::ModuleAccess(n) => n.ast_debug(w), + AttributeValue_::List(items) => { + w.write("["); + w.list(items, ", ", |w, item| { + item.value.ast_debug(w); + false + }); + w.write("]"); + }, + AttributeValue_::Range { + lo, + hi, + inclusive_hi, + } => { + lo.value.ast_debug(w); + w.write(if *inclusive_hi { "..=" } else { ".." }); + hi.value.ast_debug(w); + }, + AttributeValue_::Union(items) => { + w.list(items, " | ", |w, item| { + item.value.ast_debug(w); + false + }); + }, } } } @@ -1012,6 +1056,14 @@ impl AstDebug for Attribute_ { }); w.write(")"); }, + Attribute_::Constrained(n, op, v) => { + w.write(&format!("{}", n)); + w.write(match op { + ConstraintOp::Ne => " != ", + ConstraintOp::In => " in ", + }); + v.ast_debug(w); + }, } } } diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/translate.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/translate.rs index 0f785292bd3..9d4c53088d0 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/translate.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/expansion/translate.rs @@ -698,7 +698,8 @@ fn deprecated_attribute_location(attributes: &[P::Attributes]) -> Option { let sp!(nloc, sym) = match &attr.value { P::Attribute_::Name(n) | P::Attribute_::Assigned(n, _) - | P::Attribute_::Parameterized(n, _) => *n, + | P::Attribute_::Parameterized(n, _) + | P::Attribute_::Constrained(n, _, _) => *n, }; match KnownAttribute::resolve(sym) { Some(KnownAttribute::Deprecation(_dep)) => Some(nloc), @@ -728,11 +729,14 @@ fn unique_attributes( attributes: impl IntoIterator, ) -> E::Attributes { let mut attr_map = UniqueMap::new(); + let mut constrained_slot: u32 = 0; for sp!(loc, attr_) in attributes { + let is_constrained = matches!(&attr_, E::Attribute_::Constrained(..)); let sp!(nloc, sym) = match &attr_ { E::Attribute_::Name(n) | E::Attribute_::Assigned(n, _) - | E::Attribute_::Parameterized(n, _) => *n, + | E::Attribute_::Parameterized(n, _) + | E::Attribute_::Constrained(n, _, _) => *n, }; let name_ = match KnownAttribute::resolve(sym) { None => { @@ -797,7 +801,17 @@ fn unique_attributes( E::AttributeName_::Known(known) }, }; - if let Err((_, old_loc)) = attr_map.add(sp(nloc, name_), sp(loc, attr_)) { + // `Constrained` entries are deliberately allowed to repeat on the same parameter + // (e.g. `a in [..], a != 5`) — give each a unique slot so the `UniqueMap` accepts + // them. The `Disambiguated` key still `Display`s as the underlying name. + let key = if is_constrained { + let slot = constrained_slot; + constrained_slot += 1; + sp(nloc, E::AttributeName_::Disambiguated(sym, slot)) + } else { + sp(nloc, name_) + }; + if let Err((_, old_loc)) = attr_map.add(key, sp(loc, attr_)) { let msg = format!("Duplicate attribute '{}' attached to the same item", name_); context.env.add_diag(diag!( Declarations::DuplicateItem, @@ -826,6 +840,13 @@ fn attribute( .collect::>>()?; EA::Parameterized(n, unique_attributes(context, attr_position, true, attrs)) }, + PA::Constrained(n, op, v) => { + let op = match op { + P::ConstraintOp::Ne => E::ConstraintOp::Ne, + P::ConstraintOp::In => E::ConstraintOp::In, + }; + EA::Constrained(n, op, Box::new(attribute_value(context, *v)?)) + }, })) } @@ -919,6 +940,29 @@ fn attribute_value( )?), } }, + PV::List(items) => { + let items = items + .into_iter() + .map(|v| attribute_value(context, v)) + .collect::>>()?; + EV::List(items) + }, + PV::Range { + lo, + hi, + inclusive_hi, + } => EV::Range { + lo: Box::new(attribute_value(context, *lo)?), + hi: Box::new(attribute_value(context, *hi)?), + inclusive_hi, + }, + PV::Union(items) => { + let items = items + .into_iter() + .map(|v| attribute_value(context, v)) + .collect::>>()?; + EV::Union(items) + }, })) } diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/ast.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/ast.rs index 3013b72d5a0..3bfd3040b84 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/ast.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/ast.rs @@ -115,14 +115,28 @@ pub struct UseDecl { pub enum AttributeValue_ { Value(Value), ModuleAccess(NameAccessChain), + List(Vec), + Range { + lo: Box, + hi: Box, + inclusive_hi: bool, + }, + Union(Vec), } pub type AttributeValue = Spanned; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConstraintOp { + Ne, + In, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum Attribute_ { Name(Name), Assigned(Name, Box), Parameterized(Name, Attributes), + Constrained(Name, ConstraintOp, Box), } pub type Attribute = Spanned; @@ -133,7 +147,8 @@ impl Attribute_ { match self { Attribute_::Name(nm) | Attribute_::Assigned(nm, _) - | Attribute_::Parameterized(nm, _) => nm, + | Attribute_::Parameterized(nm, _) + | Attribute_::Constrained(nm, _, _) => nm, } } } @@ -1195,6 +1210,29 @@ impl AstDebug for AttributeValue_ { match self { AttributeValue_::Value(v) => v.ast_debug(w), AttributeValue_::ModuleAccess(n) => n.ast_debug(w), + AttributeValue_::List(items) => { + w.write("["); + w.list(items, ", ", |w, item| { + item.value.ast_debug(w); + false + }); + w.write("]"); + }, + AttributeValue_::Range { + lo, + hi, + inclusive_hi, + } => { + lo.value.ast_debug(w); + w.write(if *inclusive_hi { "..=" } else { ".." }); + hi.value.ast_debug(w); + }, + AttributeValue_::Union(items) => { + w.list(items, " | ", |w, item| { + item.value.ast_debug(w); + false + }); + }, } } } @@ -1217,6 +1255,14 @@ impl AstDebug for Attribute_ { }); w.write(")"); }, + Attribute_::Constrained(n, op, v) => { + w.write(&format!("{}", n)); + w.write(match op { + ConstraintOp::Ne => " != ", + ConstraintOp::In => " in ", + }); + v.ast_debug(w); + }, } } } diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/lexer.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/lexer.rs index 4bbbc164e26..d6464663c89 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/lexer.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/lexer.rs @@ -33,6 +33,7 @@ pub enum Tok { Minus, Period, PeriodPeriod, + PeriodPeriodEqual, Slash, Colon, ColonColon, @@ -130,6 +131,7 @@ impl fmt::Display for Tok { Minus => "-", Period => ".", PeriodPeriod => "..", + PeriodPeriodEqual => "..=", Slash => "/", Colon => ":", ColonColon => "::", @@ -649,7 +651,9 @@ fn find_token( } }, '.' => { - if text.starts_with("..") { + if text.starts_with("..=") { + (Tok::PeriodPeriodEqual, 3) + } else if text.starts_with("..") { (Tok::PeriodPeriod, 2) } else { (Tok::Period, 1) diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/syntax.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/syntax.rs index 5cffb4308f9..5a7386d730f 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/syntax.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/parser/syntax.rs @@ -714,11 +714,75 @@ fn parse_visibility(context: &mut Context) -> Result }) } -// Parse an attribute value. Either a value literal or a module access -// AttributeValue = -// -// | +// Parse an attribute value. +// AttributeValue = +// UnionValue = ( "|" )* +// RangeValue = [ ( ".." | "..=" ) ] +// PrimaryValue = +// | "[" Comma "]" +// | fn parse_attribute_value(context: &mut Context) -> Result> { + let start_loc = context.tokens.start_loc(); + let first = parse_attribute_range_value(context)?; + if context.tokens.peek() != Tok::Pipe { + return Ok(first); + } + let mut elements = vec![first]; + while match_token(context.tokens, Tok::Pipe)? { + elements.push(parse_attribute_range_value(context)?); + } + let end_loc = context.tokens.previous_end_loc(); + Ok(spanned( + context.tokens.file_hash(), + start_loc, + end_loc, + AttributeValue_::Union(elements), + )) +} + +fn parse_attribute_range_value(context: &mut Context) -> Result> { + let start_loc = context.tokens.start_loc(); + let lo = parse_attribute_primary_value(context)?; + let inclusive_hi = match context.tokens.peek() { + Tok::PeriodPeriod => false, + Tok::PeriodPeriodEqual => true, + _ => return Ok(lo), + }; + context.tokens.advance()?; + let hi = parse_attribute_primary_value(context)?; + let end_loc = context.tokens.previous_end_loc(); + Ok(spanned( + context.tokens.file_hash(), + start_loc, + end_loc, + AttributeValue_::Range { + lo: Box::new(lo), + hi: Box::new(hi), + inclusive_hi, + }, + )) +} + +fn parse_attribute_primary_value( + context: &mut Context, +) -> Result> { + let start_loc = context.tokens.start_loc(); + if context.tokens.peek() == Tok::LBracket { + let items = parse_comma_list( + context, + Tok::LBracket, + Tok::RBracket, + parse_attribute_value, + "attribute value", + )?; + let end_loc = context.tokens.previous_end_loc(); + return Ok(spanned( + context.tokens.file_hash(), + start_loc, + end_loc, + AttributeValue_::List(items), + )); + } if let Some(v) = maybe_parse_value(context)? { return Ok(sp(v.loc, AttributeValue_::Value(v))); } @@ -731,6 +795,8 @@ fn parse_attribute_value(context: &mut Context) -> Result // | "=" +// | "!=" +// | "in" // | "(" Comma ")" // AttributeName = ( "::" Identifier )* // merged into one identifier fn parse_attribute(context: &mut Context) -> Result> { @@ -747,6 +813,22 @@ fn parse_attribute(context: &mut Context) -> Result> context.tokens.advance()?; Attribute_::Assigned(n, Box::new(parse_attribute_value(context)?)) }, + Tok::ExclaimEqual => { + context.tokens.advance()?; + Attribute_::Constrained( + n, + ConstraintOp::Ne, + Box::new(parse_attribute_value(context)?), + ) + }, + Tok::Identifier if context.tokens.content() == "in" => { + context.tokens.advance()?; + Attribute_::Constrained( + n, + ConstraintOp::In, + Box::new(parse_attribute_value(context)?), + ) + }, Tok::LParen => { let args_ = parse_comma_list( context, diff --git a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs index ab2b8fb6733..dd87510d5b0 100644 --- a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs +++ b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs @@ -1188,6 +1188,18 @@ impl ModuleContext<'_> { ) } }, + Attribute::Constrained(_, name, _, _) => { + let name = fun_env.symbol_pool().string(*name); + if matches!( + name.as_str(), + well_known::PERSISTENT_ATTRIBUTE | well_known::MODULE_LOCK_ATTRIBUTE + ) { + self.error( + fun_env.get_id_loc(), + format!("attribute `{}` cannot have a constraint", name), + ) + } + }, } } if !has_persistent && fun_env.visibility() == Visibility::Public { diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs new file mode 100644 index 00000000000..170087b136d --- /dev/null +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -0,0 +1,93 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +//! Fuzz value generation for the `#[test]` attribute. +//! +//! The compiler does not pick fuzz values itself. It collects the parameter +//! constraints (`a in `, `a != `, or absence-of-spec) into a +//! [`ParamSpec`] and asks a [`FuzzValueSource`] to materialize concrete values +//! for each parameter at plan-build time. The default source ([`NoFuzzSource`]) +//! errors loudly — install a real source via [`construct_test_plan`] to enable +//! fuzz expansion. + +use move_core_types::value::MoveValue; +use move_model::{ast::AttributeValue, ty::Type}; + +/// A single inclusive/half-open range. Both endpoints are model-AST literals +/// because the compiler does not commit to a concrete representation until the +/// source materializes a sample for the parameter type. +#[derive(Debug, Clone)] +pub struct RangeSpec { + pub lo: AttributeValue, + pub hi: AttributeValue, + pub inclusive_hi: bool, +} + +/// A union of discrete literals and ranges. An empty domain is treated as +/// "unrestricted" when used as a fuzz `domain`, and as "no exclusions" when +/// used as an `exclude`. +#[derive(Debug, Clone, Default)] +pub struct Domain { + pub literals: Vec, + pub ranges: Vec, +} + +impl Domain { + pub fn is_empty(&self) -> bool { + self.literals.is_empty() && self.ranges.is_empty() + } +} + +/// What the compiler resolved for one function parameter after reading the +/// `#[test(...)]` attribute and any constraints attached to it. +#[derive(Debug, Clone)] +pub enum ParamSpec { + /// `a = ` — a single explicit value. + Concrete(MoveValue), + /// `a = [, , ...]` — a matrix that expands into N cases. + Matrix(Vec), + /// `a` not mentioned, or `a in ...` / `a != ...`. The fuzz source samples + /// `n` values from `domain` (unrestricted when empty), subject to + /// `exclude`. + Fuzz { + domain: Domain, + exclude: Domain, + }, +} + +/// Plugged in by the unit-test entrypoint. The compiler never instantiates +/// fuzz values itself; it only collects constraints. +pub trait FuzzValueSource: Send + Sync { + /// Materialize `n` values of type `ty`, drawn from `domain` (unrestricted + /// when empty) and avoiding any value in `exclude`. `seed` is provided for + /// reproducibility. + fn sample( + &self, + ty: &Type, + domain: &Domain, + exclude: &Domain, + n: usize, + seed: u64, + ) -> Result, String>; +} + +/// Default source that produces no samples and reports a clear error. Plug a +/// real implementation in to light up the fuzz path. +pub struct NoFuzzSource; + +impl FuzzValueSource for NoFuzzSource { + fn sample( + &self, + _ty: &Type, + _domain: &Domain, + _exclude: &Domain, + _n: usize, + _seed: u64, + ) -> Result, String> { + Err( + "no fuzz value source is registered; install a `FuzzValueSource` to enable \ + implicit-fuzz #[test] expansion" + .to_string(), + ) + } +} diff --git a/third_party/move/move-compiler-v2/src/lib.rs b/third_party/move/move-compiler-v2/src/lib.rs index 223287b9a2f..12978646f83 100644 --- a/third_party/move/move-compiler-v2/src/lib.rs +++ b/third_party/move/move-compiler-v2/src/lib.rs @@ -8,6 +8,7 @@ pub mod env_pipeline; mod experiments; pub mod external_checks; mod file_format_generator; +pub mod fuzz; pub mod lint_common; pub mod logging; pub mod options; diff --git a/third_party/move/move-compiler-v2/src/lint_common.rs b/third_party/move/move-compiler-v2/src/lint_common.rs index 87c25b4b246..b3e101c8cf1 100644 --- a/third_party/move/move-compiler-v2/src/lint_common.rs +++ b/third_party/move/move-compiler-v2/src/lint_common.rs @@ -42,6 +42,16 @@ fn parse_lint_skip_attribute( ); BTreeSet::new() }, + Attribute::Constrained(id, ..) => { + env.error( + &env.get_node_loc(*id), + &format!( + "expected `#[{}(...)]`, not a constrained value", + LintAttribute::SKIP + ), + ); + BTreeSet::new() + }, Attribute::Apply(id, _, attrs) => { if attrs.is_empty() { env.error( @@ -59,6 +69,13 @@ fn parse_lint_skip_attribute( ); None }, + Attribute::Constrained(id, ..) => { + env.error( + &env.get_node_loc(*id), + "did not expect a constrained value, expected only the names of the lint checks to be skipped", + ); + None + }, Attribute::Apply(id, name, sub_attrs) => { if !sub_attrs.is_empty() { env.error(&env.get_node_loc(*id), "unexpected nested attributes"); diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index f0a4bf6dbc4..8b9702d7940 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -11,7 +11,10 @@ //! includes info about each '#[test]' function: name, arguments to provide, and expected failure or //! success. -use crate::options::Options; +use crate::{ + fuzz::{Domain, FuzzValueSource, NoFuzzSource, ParamSpec, RangeSpec}, + options::Options, +}; use codespan_reporting::diagnostic::Severity; use legacy_move_compiler::{ shared::known_attributes::{AttributeKind, TestingAttribute}, @@ -22,7 +25,7 @@ use move_core_types::{ identifier::Identifier, language_storage::ModuleId, value::MoveValue, vm_status::StatusCode, }; use move_model::{ - ast::{Address, Attribute, AttributeValue, ModuleName, Value}, + ast::{Address, Attribute, AttributeValue, ConstraintOp, ModuleName, Value}, model::{FunctionEnv, GlobalEnv, Loc, ModuleEnv, Parameter}, symbol::Symbol, ty::{PrimitiveType, Type}, @@ -30,6 +33,13 @@ use move_model::{ use num::{BigInt, ToPrimitive}; use std::collections::BTreeMap; +/// Default number of values to draw per fuzzed parameter. +const DEFAULT_FUZZ_ITERATIONS: usize = 16; +/// Default deterministic seed if the caller does not override. +const DEFAULT_FUZZ_SEED: u64 = 0; +/// Cap on Cartesian-product expansion to guard against accidental explosion. +const MAX_FUZZ_CASES: usize = 1024; + //*************************************************************************** // Test Plan Building //*************************************************************************** @@ -39,6 +49,16 @@ use std::collections::BTreeMap; pub fn construct_test_plan( env: &GlobalEnv, package_filter: Option, +) -> Option> { + construct_test_plan_with_fuzz_source(env, package_filter, &NoFuzzSource) +} + +/// Like [`construct_test_plan`], but the caller can supply a [`FuzzValueSource`] to materialize +/// values for implicit-fuzz or `in`/`!=` constrained parameters. +pub fn construct_test_plan_with_fuzz_source( + env: &GlobalEnv, + package_filter: Option, + fuzz_source: &dyn FuzzValueSource, ) -> Option> { let options = env.get_extension::().expect("options"); if !options.compile_test_code { @@ -49,7 +69,7 @@ pub fn construct_test_plan( env.get_modules() .filter_map(|module| { if module.is_primary_target() { - construct_module_test_plan(env, package_filter, module) + construct_module_test_plan(env, package_filter, fuzz_source, module) } else { None } @@ -61,6 +81,7 @@ pub fn construct_test_plan( fn construct_module_test_plan( env: &GlobalEnv, _package_filter: Option, + fuzz_source: &dyn FuzzValueSource, module: ModuleEnv, ) -> Option { // TODO (#12885): what is a package? Do we need this code? @@ -71,11 +92,8 @@ fn construct_module_test_plan( let current_module = module.get_name(); let tests: BTreeMap<_, _> = module .get_functions() - .filter_map(|func| { - let func_name = func.get_name_str(); - build_test_info(env, current_module, func) - .map(|test_case| (func_name.clone(), test_case)) - }) + .flat_map(|func| build_test_info(env, current_module, fuzz_source, func).into_iter()) + .map(|test_case| (test_case.test_name.clone(), test_case)) .collect(); let module_id = module.get_identifier(); @@ -108,8 +126,9 @@ fn construct_module_test_plan( fn build_test_info( env: &GlobalEnv, current_module: &ModuleName, + fuzz_source: &dyn FuzzValueSource, function: FunctionEnv, -) -> Option { +) -> Vec { let fn_name_str = function.get_name_str(); let fn_id_loc = function.get_id_loc(); @@ -132,7 +151,7 @@ fn build_test_info( let abort_loc = env.get_node_loc(abort_id); env.error_with_labels(&fn_id_loc, fn_msg, vec![(abort_loc, abort_msg.to_string())]); } - return None; + return Vec::new(); }, Some(test_attribute) => test_attribute, }; @@ -157,112 +176,421 @@ fn build_test_info( ]); } - let test_annotation_params = parse_test_attribute(env, test_attribute, 0); + let specs = match parse_test_attribute(env, test_attribute, 0) { + Some(specs) => specs, + None => return Vec::new(), + }; - let mut arguments = Vec::new(); - for param in function.get_parameters_ref() { - let Parameter(var, ty, var_loc) = ¶m; + let parameters: Vec<_> = function.get_parameters_ref().iter().cloned().collect(); - match test_annotation_params.get(var) { - Some(MoveValue::Address(addr)) => match ty { - Type::Primitive(PrimitiveType::Signer) => arguments.push(MoveValue::Signer(*addr)), - Type::Reference(_, inner) if **inner == Type::Primitive(PrimitiveType::Signer) => { - arguments.push(MoveValue::Signer(*addr)); - }, - Type::Primitive(PrimitiveType::Address) => { - arguments.push(MoveValue::Address(*addr)) - }, - _ => { - let err_msg = "Unexpected argument type: expect an address or a signer"; - let invalid_test = "unable to generate test"; - env.error_with_labels(&fn_id_loc, invalid_test, vec![ - (test_attribute_loc.clone(), err_msg.to_string()), - ( - var_loc.clone(), - "Corresponding to this parameter".to_string(), - ), - ]); - }, - }, - Some(value) => arguments.push(value.clone()), + // For each parameter, materialize one dimension of MoveValues. + let mut had_error = false; + let mut had_fuzz = false; + let mut dimensions: Vec<(Symbol, Vec)> = Vec::with_capacity(parameters.len()); + for param in ¶meters { + let Parameter(var, ty, var_loc) = param; + // Synthesize an implicit-fuzz spec when no spec was given for this param. + let owned_default; + let spec_ref = match specs.get(var) { + Some(s) => s, None => { - let missing_param_msg = "Missing test parameter assignment in test. Expected a \ - parameter to be assigned in this attribute"; - let invalid_test = "unable to generate test"; - env.error_with_labels(&fn_id_loc, invalid_test, vec![ - (test_attribute_loc.clone(), missing_param_msg.to_string()), - ( - var_loc.clone(), - "Corresponding to this parameter".to_string(), - ), - ]); + owned_default = ParamSpec::Fuzz { + domain: Domain::default(), + exclude: Domain::default(), + }; + &owned_default }, + }; + match materialize_param_values( + env, + fuzz_source, + &fn_id_loc, + &test_attribute_loc, + var_loc, + ty, + spec_ref, + ) { + Some(values) => { + if matches!(spec_ref, ParamSpec::Fuzz { .. }) { + had_fuzz = true; + } + dimensions.push((*var, values)); + }, + None => had_error = true, } } + if had_error { + return Vec::new(); + } + let expected_failure = match abort_attribute_opt { None => None, Some(abort_attribute) => parse_failure_attribute(env, current_module, abort_attribute), }; - Some(TestCase { - test_name: fn_name_str.to_string(), - arguments, - expected_failure, - }) + // Cartesian product across all parameter dimensions. + let total: usize = dimensions + .iter() + .map(|(_, vs)| vs.len()) + .product::() + .max(1); + if total > MAX_FUZZ_CASES { + env.error( + &fn_id_loc, + &format!( + "#[test] expansion would produce {} cases (cap: {}). Narrow the matrix, fuzz \ + domain, or `--fuzz-iterations`.", + total, MAX_FUZZ_CASES + ), + ); + return Vec::new(); + } + + if had_fuzz { + env.diag( + Severity::Note, + &fn_id_loc, + &format!( + "fuzz: expanded `{}` to {} case{}", + fn_name_str, + total, + if total == 1 { "" } else { "s" } + ), + ); + } + + if dimensions.is_empty() { + // Zero-arg function: a single case with no arguments and the bare function name. + return vec![TestCase { + test_name: fn_name_str.to_string(), + arguments: Vec::new(), + expected_failure, + }]; + } + + // If every dimension has exactly one value, emit a single TestCase with the bare function + // name (preserves existing test-name behavior for non-expanded #[test] functions). + let is_single = dimensions.iter().all(|(_, vs)| vs.len() == 1); + + let mut cases = Vec::with_capacity(total); + let mut indices = vec![0usize; dimensions.len()]; + loop { + let mut arguments = Vec::with_capacity(dimensions.len()); + let mut suffix_parts = Vec::with_capacity(dimensions.len()); + for (i, (var, vs)) in dimensions.iter().enumerate() { + let v = &vs[indices[i]]; + arguments.push(v.clone()); + suffix_parts.push(format!( + "{}={}", + var.display(env.symbol_pool()), + format_move_value(v) + )); + } + let test_name = if is_single { + fn_name_str.to_string() + } else { + format!("{}[{}]", fn_name_str, suffix_parts.join(",")) + }; + cases.push(TestCase { + test_name, + arguments, + expected_failure: expected_failure.clone(), + }); + // Advance odometer. + let mut idx = dimensions.len(); + loop { + if idx == 0 { + return cases; + } + idx -= 1; + indices[idx] += 1; + if indices[idx] < dimensions[idx].1.len() { + break; + } + indices[idx] = 0; + } + } +} + +/// Compact human-readable rendering for a `MoveValue`, used in expanded +/// test-case suffixes like `foo[a=@0x1,b=42]`. +fn format_move_value(v: &MoveValue) -> String { + match v { + MoveValue::Address(a) | MoveValue::Signer(a) => format!("@{}", a.short_str_lossless()), + MoveValue::U8(x) => x.to_string(), + MoveValue::U16(x) => x.to_string(), + MoveValue::U32(x) => x.to_string(), + MoveValue::U64(x) => x.to_string(), + MoveValue::U128(x) => x.to_string(), + MoveValue::U256(x) => x.to_string(), + MoveValue::Bool(b) => b.to_string(), + other => format!("{:?}", other), + } +} + +/// Turn a [`ParamSpec`] into the concrete list of `MoveValue`s for that parameter. +/// Returns `None` and reports an error on type mismatch or fuzz-source failure. +fn materialize_param_values( + env: &GlobalEnv, + fuzz_source: &dyn FuzzValueSource, + fn_id_loc: &Loc, + test_attribute_loc: &Loc, + var_loc: &Loc, + ty: &Type, + spec: &ParamSpec, +) -> Option> { + match spec { + ParamSpec::Concrete(v) => coerce_to_param_type(env, fn_id_loc, test_attribute_loc, var_loc, ty, v.clone()) + .map(|v| vec![v]), + ParamSpec::Matrix(vs) => { + let mut out = Vec::with_capacity(vs.len()); + for v in vs { + let coerced = coerce_to_param_type( + env, + fn_id_loc, + test_attribute_loc, + var_loc, + ty, + v.clone(), + )?; + out.push(coerced); + } + Some(out) + }, + ParamSpec::Fuzz { domain, exclude } => { + match fuzz_source.sample(ty, domain, exclude, DEFAULT_FUZZ_ITERATIONS, DEFAULT_FUZZ_SEED) + { + Ok(vs) if vs.is_empty() => { + env.error_with_labels(fn_id_loc, "unable to generate test", vec![ + ( + test_attribute_loc.clone(), + "Fuzz source returned no values for this parameter".to_string(), + ), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); + None + }, + Ok(vs) => Some(vs), + Err(msg) => { + env.error_with_labels(fn_id_loc, "unable to generate test", vec![ + (test_attribute_loc.clone(), msg), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); + None + }, + } + }, + } +} + +/// Apply the same signer/address coercion logic the legacy `#[test(a = @0x..)]` +/// code used. Returns `None` and reports an error on type mismatch. +fn coerce_to_param_type( + env: &GlobalEnv, + fn_id_loc: &Loc, + test_attribute_loc: &Loc, + var_loc: &Loc, + ty: &Type, + value: MoveValue, +) -> Option { + match (&value, ty) { + (MoveValue::Address(addr), Type::Primitive(PrimitiveType::Signer)) => { + Some(MoveValue::Signer(*addr)) + }, + (MoveValue::Address(addr), Type::Reference(_, inner)) + if **inner == Type::Primitive(PrimitiveType::Signer) => + { + Some(MoveValue::Signer(*addr)) + }, + (MoveValue::Address(_), Type::Primitive(PrimitiveType::Address)) => Some(value), + _ => { + let err_msg = "Unexpected argument type: expect an address or a signer"; + let invalid_test = "unable to generate test"; + env.error_with_labels(fn_id_loc, invalid_test, vec![ + (test_attribute_loc.clone(), err_msg.to_string()), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); + None + }, + } } //*************************************************************************** // Attribute parsers //*************************************************************************** +/// Parse the contents of `#[test(...)]` into one [`ParamSpec`] per named +/// parameter. Returns `None` if a fatal structural error was encountered (and +/// the caller should abandon test-case generation for this function). fn parse_test_attribute( env: &GlobalEnv, test_attribute: &Attribute, depth: usize, -) -> BTreeMap { +) -> Option> { match test_attribute { Attribute::Apply(id, _, _) if depth > 0 => { let aloc = env.get_node_loc(*id); env.error(&aloc, "Unexpected nested attribute in test declaration"); - BTreeMap::new() + None }, - Attribute::Apply(_id, sym, vec) => { + Attribute::Apply(_id, sym, inner) => { assert!( *TestingAttribute::TEST == env.symbol_pool().string(*sym).to_string(), "ICE: We should only be parsing a raw test attribute" ); - vec.iter() - .flat_map(|attr| parse_test_attribute(env, attr, depth + 1)) - .collect() - }, - Attribute::Assign(id, sym, val) => { - if depth != 1 { - let aloc = env.get_node_loc(*id); - env.error(&aloc, "Unexpected nested attribute in test declaration"); - return BTreeMap::new(); + let mut specs: BTreeMap = BTreeMap::new(); + for attr in inner { + if !merge_test_param_entry(env, &mut specs, attr) { + // entry-level errors have already been reported; keep processing the rest + } } + Some(specs) + }, + Attribute::Assign(id, _, _) | Attribute::Constrained(id, _, _, _) => { + let aloc = env.get_node_loc(*id); + env.error( + &aloc, + "Unexpected top-level form for #[test]; expected `#[test(...)]`", + ); + None + }, + } +} - let value = match convert_attribute_value_to_move_value(env, val) { - Some(move_value) => move_value, - None => { - let aloc = env.get_node_loc(*id); - let assign_loc = env.get_node_loc(*id); - env.error_with_labels(&assign_loc, "Unsupported attribute value", vec![( - aloc, - "Assigned in this attribute".to_string(), - )]); - return BTreeMap::new(); +/// Process one entry within `#[test(...)]` (e.g. `a = @0x1`, `a in 1..=10`, +/// `a != [..]`) and merge it into `specs`. Returns `true` on success. +fn merge_test_param_entry( + env: &GlobalEnv, + specs: &mut BTreeMap, + attr: &Attribute, +) -> bool { + match attr { + Attribute::Assign(id, sym, val) => { + let entry_loc = env.get_node_loc(*id); + // List literal on the RHS expands to a Matrix; anything else is a single value. + let new_spec = match val { + AttributeValue::List(_, items) => { + let mut values = Vec::with_capacity(items.len()); + for item in items { + match convert_attribute_value_to_move_value(env, item) { + Some(v) => values.push(v), + None => { + let iloc = attribute_value_loc(env, item); + env.error(&iloc, "Unsupported value in test matrix"); + return false; + }, + } + } + ParamSpec::Matrix(values) + }, + _ => match convert_attribute_value_to_move_value(env, val) { + Some(v) => ParamSpec::Concrete(v), + None => { + env.error_with_labels(&entry_loc, "Unsupported attribute value", vec![( + entry_loc.clone(), + "Assigned in this attribute".to_string(), + )]); + return false; + }, }, }; + insert_or_reject(env, specs, *sym, new_spec, &entry_loc) + }, + Attribute::Constrained(id, sym, op, val) => { + let entry_loc = env.get_node_loc(*id); + // Build/extend a Fuzz spec for this parameter. + let existing = specs.remove(sym); + let (mut domain, mut exclude) = match existing { + None => (Domain::default(), Domain::default()), + Some(ParamSpec::Fuzz { domain, exclude }) => (domain, exclude), + Some(_) => { + env.error( + &entry_loc, + "Cannot mix `=` with `!=` / `in` for the same parameter", + ); + return false; + }, + }; + let target = match op { + ConstraintOp::In => &mut domain, + ConstraintOp::Ne => &mut exclude, + }; + fold_into_domain(val, target); + specs.insert(*sym, ParamSpec::Fuzz { domain, exclude }); + true + }, + Attribute::Apply(id, _, _) => { + let aloc = env.get_node_loc(*id); + env.error(&aloc, "Unexpected nested attribute in test declaration"); + false + }, + } +} - let mut args = BTreeMap::new(); - args.insert(*sym, value); - args +/// Insert `new_spec` for `sym`, or report a duplicate / mixed-form error. +fn insert_or_reject( + env: &GlobalEnv, + specs: &mut BTreeMap, + sym: Symbol, + new_spec: ParamSpec, + entry_loc: &Loc, +) -> bool { + if specs.contains_key(&sym) { + env.error( + entry_loc, + "Duplicate or conflicting spec for this parameter (use one of `=`, `in`, or `!=`)", + ); + return false; + } + specs.insert(sym, new_spec); + true +} + +/// Flatten a model-AST `AttributeValue` into literals and ranges inside the +/// given [`Domain`]. Unions and nested lists are flattened recursively; +/// anything else lands in `literals`. +fn fold_into_domain(value: &AttributeValue, dom: &mut Domain) { + match value { + AttributeValue::Range { + lo, + hi, + inclusive_hi, + .. + } => dom.ranges.push(RangeSpec { + lo: (**lo).clone(), + hi: (**hi).clone(), + inclusive_hi: *inclusive_hi, + }), + AttributeValue::List(_, items) | AttributeValue::Union(_, items) => { + for item in items { + fold_into_domain(item, dom); + } }, + leaf => dom.literals.push(leaf.clone()), } } +fn attribute_value_loc(env: &GlobalEnv, value: &AttributeValue) -> Loc { + let id = match value { + AttributeValue::Value(id, _) => *id, + AttributeValue::Name(id, _, _) => *id, + AttributeValue::List(id, _) => *id, + AttributeValue::Range { id, .. } => *id, + AttributeValue::Union(id, _) => *id, + }; + env.get_node_loc(id) +} + fn parse_failure_attribute( env: &GlobalEnv, current_module: &ModuleName, @@ -280,6 +608,14 @@ fn parse_failure_attribute( )]); None }, + Attribute::Constrained(id, _, _, _) => { + let aloc = env.get_node_loc(*id); + env.error( + &aloc, + "Constraint operators (`!=`, `in`) are not supported in #[expected_failure(...)]", + ); + None + }, Attribute::Apply(id, sym, attrs) => { assert!( TestingAttribute::EXPECTED_FAILURE == env.symbol_pool().string(*sym).to_string(), @@ -493,6 +829,15 @@ fn check_attribute_unassigned(env: &GlobalEnv, kind: &str, attr: Attribute) -> O env.error(&attr_loc, &msg); None }, + Attribute::Constrained(id, sym, _, _) => { + assert!(env.symbol_pool().string(sym).to_string() == kind); + let attr_loc = env.get_node_loc(id); + env.error( + &attr_loc, + "Constraint operators (`!=`, `in`) are not supported in expected failure attributes", + ); + None + }, } } @@ -516,6 +861,14 @@ fn get_assigned_attribute( env.error(&loc, &msg); None }, + Attribute::Constrained(id, _, _, _) => { + let loc = env.get_node_loc(id); + env.error( + &loc, + "Constraint operators (`!=`, `in`) are not supported in expected failure attributes", + ); + None + }, } } @@ -541,6 +894,16 @@ fn convert_location(env: &GlobalEnv, attr: Attribute) -> Option { )]); None }, + AttributeValue::List(id, _) + | AttributeValue::Range { id, .. } + | AttributeValue::Union(id, _) => { + let vloc = env.get_node_loc(id); + env.error_with_labels(&loc, "invalid attribute value", vec![( + vloc, + "Expected a module identifier, e.g. 'std::vector'".to_string(), + )]); + None + }, } } @@ -562,6 +925,16 @@ fn convert_constant_value_u64_constant_or_value( let vloc = env.get_node_loc(*id); (vloc, opt_module_name, sym) }, + AttributeValue::List(id, _) + | AttributeValue::Range { id, .. } + | AttributeValue::Union(id, _) => { + let loc = env.get_node_loc(*id); + env.error( + &loc, + "Expected a numeric constant or value; list, range, and union forms are not supported here", + ); + return None; + }, }; let module_env: ModuleEnv = if let Some(module_name) = opt_module_name { if let Some(module_env) = env.find_module(module_name) { diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp new file mode 100644 index 00000000000..d43293de1f9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp @@ -0,0 +1,57 @@ + +Diagnostics: +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:6:16 + │ +5 │ #[test(_a != @0x42)] + │ ----------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +6 │ public fun ne_single(_a: signer) { } + │ ^^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:9:16 + │ +8 │ #[test(_a != [@0x42, @0x41])] + │ -------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +9 │ public fun ne_list(_a: signer) { } + │ ^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:12:16 + │ +11 │ #[test(_a in [@0x1, @0x2, @0x3])] + │ ------------------------------ no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +12 │ public fun in_list(_a: signer) { } + │ ^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:15:16 + │ +14 │ #[test(_a in 1..=10)] + │ ------------------ no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +15 │ public fun in_inclusive_range(_a: signer) { } + │ ^^^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:18:16 + │ +17 │ #[test(_a in 1..10)] + │ ----------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +18 │ public fun in_half_open_range(_a: signer) { } + │ ^^^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:21:16 + │ +20 │ #[test(_a in @0x1 | @0x5..=@0x10 | @0x20)] + │ --------------------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +21 │ public fun in_union(_a: signer) { } + │ ^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_constraints.move:26:16 + │ +25 │ #[test(_a in [@0x1, @0x2, @0x3], _a != @0x2)] + │ ------------------------------------------ no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +26 │ public fun in_with_excludes(_a: signer) { } + │ ^^^^^^^^^^^^^^^^ -- Corresponding to this parameter diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.move new file mode 100644 index 00000000000..cf87522c497 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.move @@ -0,0 +1,27 @@ +// New grammar: `name in ` and `name != ` build a fuzz spec. +// Parser acceptance is asserted by the absence of a parse error; with no +// FuzzValueSource registered the planner reports a clear diagnostic. +module 0x1::M { + #[test(_a != @0x42)] + public fun ne_single(_a: signer) { } + + #[test(_a != [@0x42, @0x41])] + public fun ne_list(_a: signer) { } + + #[test(_a in [@0x1, @0x2, @0x3])] + public fun in_list(_a: signer) { } + + #[test(_a in 1..=10)] + public fun in_inclusive_range(_a: signer) { } + + #[test(_a in 1..10)] + public fun in_half_open_range(_a: signer) { } + + #[test(_a in @0x1 | @0x5..=@0x10 | @0x20)] + public fun in_union(_a: signer) { } + + // Combining `in` and `!=` on the same parameter is allowed; the domain + // narrows and the exclude set accumulates. + #[test(_a in [@0x1, @0x2, @0x3], _a != @0x2)] + public fun in_with_excludes(_a: signer) { } +} diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp new file mode 100644 index 00000000000..92cc851f4bf --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp @@ -0,0 +1,25 @@ + +Diagnostics: +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_implicit.move:6:16 + │ +5 │ #[test] + │ ---- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +6 │ public fun bare_with_signer(_a: signer) { } + │ ^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_implicit.move:9:16 + │ +8 │ #[test] + │ ---- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +9 │ public fun bare_with_two(_a: signer, _b: address) { } + │ ^^^^^^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_implicit.move:9:16 + │ +8 │ #[test] + │ ---- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +9 │ public fun bare_with_two(_a: signer, _b: address) { } + │ ^^^^^^^^^^^^^ -- Corresponding to this parameter diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move new file mode 100644 index 00000000000..b5b406736f7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move @@ -0,0 +1,14 @@ +// Bare #[test] on a function with parameters now treats the parameters as +// implicit fuzz inputs. With no FuzzValueSource registered the compiler reports +// a clear diagnostic instead of the old "Missing test parameter assignment". +module 0x1::M { + #[test] + public fun bare_with_signer(_a: signer) { } + + #[test] + public fun bare_with_two(_a: signer, _b: address) { } + + // No parameters: no fuzz, no error. + #[test] + public fun bare_zero_args() { } +} diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.exp new file mode 100644 index 00000000000..90b32906711 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.exp @@ -0,0 +1,2 @@ + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.move new file mode 100644 index 00000000000..bff09207b52 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_matrix.move @@ -0,0 +1,12 @@ +// Matrix expansion: `a = [...]` produces one test case per element. +module 0x1::M { + #[test(_a = [@0x1, @0x2, @0x3])] + public fun matrix_single(_a: signer) { } + + #[test(_a = [@0x1, @0x2], _b = [@0xa, @0xb])] + public fun matrix_cartesian(_a: signer, _b: signer) { } + + // Singleton matrix [v] behaves like `a = v`. + #[test(_a = [@0x1])] + public fun matrix_singleton(_a: signer) { } +} diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp new file mode 100644 index 00000000000..7045cbafc23 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp @@ -0,0 +1,29 @@ + +Diagnostics: +error: Cannot mix `=` with `!=` / `in` for the same parameter + ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:3:23 + │ +3 │ #[test(_a = @0x1, _a != @0x2)] + │ ^^^^^^^^^^ + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:4:16 + │ +3 │ #[test(_a = @0x1, _a != @0x2)] + │ --------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +4 │ public fun mix_eq_then_ne(_a: signer) { } + │ ^^^^^^^^^^^^^^ -- Corresponding to this parameter + +error: Cannot mix `=` with `!=` / `in` for the same parameter + ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:6:12 + │ +6 │ #[test(_a != @0x2, _a = @0x1)] + │ ^^^^^^^^^^ + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:7:16 + │ +6 │ #[test(_a != @0x2, _a = @0x1)] + │ --------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion +7 │ public fun mix_ne_then_eq(_a: signer) { } + │ ^^^^^^^^^^^^^^ -- Corresponding to this parameter diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.move new file mode 100644 index 00000000000..f8011125026 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.move @@ -0,0 +1,8 @@ +// Cannot mix `=` with `!=` / `in` on the same parameter. +module 0x1::M { + #[test(_a = @0x1, _a != @0x2)] + public fun mix_eq_then_ne(_a: signer) { } + + #[test(_a != @0x2, _a = @0x1)] + public fun mix_ne_then_eq(_a: signer) { } +} diff --git a/third_party/move/move-model/src/ast.rs b/third_party/move/move-model/src/ast.rs index 462901dbf53..4a9183adb3e 100644 --- a/third_party/move/move-model/src/ast.rs +++ b/third_party/move/move-model/src/ast.rs @@ -70,18 +70,35 @@ pub struct SpecFunDecl { pub enum AttributeValue { Value(NodeId, Value), Name(NodeId, Option, Symbol), + List(NodeId, Vec), + Range { + id: NodeId, + lo: Box, + hi: Box, + inclusive_hi: bool, + }, + Union(NodeId, Vec), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConstraintOp { + Ne, + In, } #[derive(Debug, Clone)] pub enum Attribute { Apply(NodeId, Symbol, Vec), Assign(NodeId, Symbol, AttributeValue), + Constrained(NodeId, Symbol, ConstraintOp, AttributeValue), } impl Attribute { pub fn name(&self) -> Symbol { match self { - Attribute::Assign(_, s, _) | Attribute::Apply(_, s, _) => *s, + Attribute::Assign(_, s, _) + | Attribute::Apply(_, s, _) + | Attribute::Constrained(_, s, _, _) => *s, } } @@ -91,7 +108,9 @@ impl Attribute { pub fn node_id(&self) -> NodeId { match self { - Attribute::Assign(id, _, _) | Attribute::Apply(id, _, _) => *id, + Attribute::Assign(id, _, _) + | Attribute::Apply(id, _, _) + | Attribute::Constrained(id, _, _, _) => *id, } } } diff --git a/third_party/move/move-model/src/builder/module_builder.rs b/third_party/move/move-model/src/builder/module_builder.rs index 13eda135ea3..eb743eb23d5 100644 --- a/third_party/move/move-model/src/builder/module_builder.rs +++ b/third_party/move/move-model/src/builder/module_builder.rs @@ -4,10 +4,10 @@ use crate::{ ast::{ - AccessSpecifier, Address, Attribute, AttributeValue, Condition, ConditionKind, Exp, - ExpData, FriendDecl, ModuleName, Operation, Pattern, PropertyBag, PropertyValue, - QualifiedSymbol, Spec, SpecBlockInfo, SpecBlockTarget, SpecFunDecl, SpecVarDecl, TempIndex, - UseDecl, Value, + AccessSpecifier, Address, Attribute, AttributeValue, Condition, ConditionKind, + ConstraintOp, Exp, ExpData, FriendDecl, ModuleName, Operation, Pattern, PropertyBag, + PropertyValue, QualifiedSymbol, Spec, SpecBlockInfo, SpecBlockTarget, SpecFunDecl, + SpecVarDecl, TempIndex, UseDecl, Value, }, builder::{ exp_builder::ExpTranslator, @@ -400,66 +400,102 @@ impl ModuleBuilder<'_, '_> { Attribute::Apply(node_id, sym, self.translate_attributes(vs)) }, EA::Attribute_::Assigned(n, v) => { - let value_node_id = self - .parent - .env - .new_node(self.parent.to_loc(&v.loc), Type::Tuple(vec![])); - let v = match &v.value { - EA::AttributeValue_::Value(val) => { - let val = if let Some((val, _)) = ExpTranslator::new(self) - .translate_value_free(val, &ErrorMessageContext::General) - { - val - } else { - // Error reported - Value::Bool(false) - }; - AttributeValue::Value(value_node_id, val) - }, - EA::AttributeValue_::Module(mident) => { - let addr_bytes = self.parent.resolve_address( - &self.parent.to_loc(&mident.loc), - &mident.value.address, - ); - let module_name = ModuleName::from_address_bytes_and_name( - addr_bytes, - self.symbol_pool() - .make(mident.value.module.0.value.as_str()), - ); - // TODO support module attributes more than via empty string - AttributeValue::Name( - value_node_id, - Some(module_name), - self.symbol_pool().make(""), - ) - }, - EA::AttributeValue_::ModuleAccess(macc) => match macc.value { - EA::ModuleAccess_::Name(n) => AttributeValue::Name( - value_node_id, - None, - self.symbol_pool().make(n.value.as_str()), - ), - EA::ModuleAccess_::ModuleAccess(mident, n, _) => { - let (_, macc) = self.check_no_variant_and_convert_maccess(macc); - let addr_bytes = self.parent.resolve_address( - &self.parent.to_loc(&macc.loc), - &mident.value.address, - ); - let module_name = ModuleName::from_address_bytes_and_name( - addr_bytes, - self.symbol_pool() - .make(mident.value.module.0.value.as_str()), - ); - AttributeValue::Name( - value_node_id, - Some(module_name), - self.symbol_pool().make(n.value.as_str()), - ) - }, - }, - }; + let v = self.translate_attribute_value(v); Attribute::Assign(node_id, self.symbol_pool().make(n.value.as_str()), v) }, + EA::Attribute_::Constrained(n, op, v) => { + let v = self.translate_attribute_value(v); + let op = match op { + EA::ConstraintOp::Ne => ConstraintOp::Ne, + EA::ConstraintOp::In => ConstraintOp::In, + }; + Attribute::Constrained(node_id, self.symbol_pool().make(n.value.as_str()), op, v) + }, + } + } + + fn translate_attribute_value(&mut self, v: &EA::AttributeValue) -> AttributeValue { + let value_node_id = self + .parent + .env + .new_node(self.parent.to_loc(&v.loc), Type::Tuple(vec![])); + match &v.value { + EA::AttributeValue_::Value(val) => { + let val = if let Some((val, _)) = ExpTranslator::new(self) + .translate_value_free(val, &ErrorMessageContext::General) + { + val + } else { + // Error reported + Value::Bool(false) + }; + AttributeValue::Value(value_node_id, val) + }, + EA::AttributeValue_::Module(mident) => { + let addr_bytes = self.parent.resolve_address( + &self.parent.to_loc(&mident.loc), + &mident.value.address, + ); + let module_name = ModuleName::from_address_bytes_and_name( + addr_bytes, + self.symbol_pool() + .make(mident.value.module.0.value.as_str()), + ); + // TODO support module attributes more than via empty string + AttributeValue::Name( + value_node_id, + Some(module_name), + self.symbol_pool().make(""), + ) + }, + EA::AttributeValue_::ModuleAccess(macc) => match macc.value { + EA::ModuleAccess_::Name(n) => AttributeValue::Name( + value_node_id, + None, + self.symbol_pool().make(n.value.as_str()), + ), + EA::ModuleAccess_::ModuleAccess(mident, n, _) => { + let (_, macc) = self.check_no_variant_and_convert_maccess(macc); + let addr_bytes = self.parent.resolve_address( + &self.parent.to_loc(&macc.loc), + &mident.value.address, + ); + let module_name = ModuleName::from_address_bytes_and_name( + addr_bytes, + self.symbol_pool() + .make(mident.value.module.0.value.as_str()), + ); + AttributeValue::Name( + value_node_id, + Some(module_name), + self.symbol_pool().make(n.value.as_str()), + ) + }, + }, + EA::AttributeValue_::List(items) => { + let items = items + .iter() + .map(|item| self.translate_attribute_value(item)) + .collect(); + AttributeValue::List(value_node_id, items) + }, + EA::AttributeValue_::Range { + lo, + hi, + inclusive_hi, + } => AttributeValue::Range { + id: value_node_id, + lo: Box::new(self.translate_attribute_value(lo)), + hi: Box::new(self.translate_attribute_value(hi)), + inclusive_hi: *inclusive_hi, + }, + EA::AttributeValue_::Union(items) => { + let items = items + .iter() + .map(|item| self.translate_attribute_value(item)) + .collect(); + AttributeValue::Union(value_node_id, items) + }, } } } diff --git a/third_party/move/move-prover/move-docgen/src/docgen.rs b/third_party/move/move-prover/move-docgen/src/docgen.rs index dd5a75e2bee..8340831dc6c 100644 --- a/third_party/move/move-prover/move-docgen/src/docgen.rs +++ b/third_party/move/move-prover/move-docgen/src/docgen.rs @@ -565,6 +565,47 @@ impl<'env> Docgen<'env> { } } + /// Gets a readable version of an attribute value. + fn gen_attribute_value(&self, value: &AttributeValue) -> String { + match value { + AttributeValue::Value(_node_id, value) => self.env.display(value).to_string(), + AttributeValue::Name(_node_id, module_name_option, symbol2) => { + let symbol2_name = self.name_string(*symbol2).to_string(); + let module_prefix = match module_name_option { + None => "".to_string(), + Some(ref module_name) => { + format!("{}::", module_name.display_full(self.env)) + }, + }; + format!("{}{}", module_prefix, symbol2_name) + }, + AttributeValue::List(_, items) => { + let inner = items + .iter() + .map(|i| self.gen_attribute_value(i)) + .join(", "); + format!("[{}]", inner) + }, + AttributeValue::Range { + lo, + hi, + inclusive_hi, + .. + } => { + format!( + "{}{}{}", + self.gen_attribute_value(lo), + if *inclusive_hi { "..=" } else { ".." }, + self.gen_attribute_value(hi) + ) + }, + AttributeValue::Union(_, items) => items + .iter() + .map(|i| self.gen_attribute_value(i)) + .join(" | "), + } + } + /// Gets a readable version of an attribute. fn gen_attribute(&self, attribute: &Attribute) -> String { let annotation_body: String = match attribute { @@ -579,22 +620,24 @@ impl<'env> Docgen<'env> { }, Attribute::Assign(_node_id, symbol, attribute_value) => { let symbol_string = self.name_string(*symbol).to_string(); - match attribute_value { - AttributeValue::Value(_node_id, value) => { - let value_string = self.env.display(value); - format!("{} = {}", symbol_string, value_string) - }, - AttributeValue::Name(_node_id, module_name_option, symbol2) => { - let symbol2_name = self.name_string(*symbol2).to_string(); - let module_prefix = match module_name_option { - None => "".to_string(), - Some(ref module_name) => { - format!("{}::", module_name.display_full(self.env)) - }, - }; - format!("{} = {}{}", symbol_string, module_prefix, symbol2_name) - }, - } + format!( + "{} = {}", + symbol_string, + self.gen_attribute_value(attribute_value) + ) + }, + Attribute::Constrained(_node_id, symbol, op, attribute_value) => { + let symbol_string = self.name_string(*symbol).to_string(); + let op_str = match op { + move_model::ast::ConstraintOp::Ne => "!=", + move_model::ast::ConstraintOp::In => "in", + }; + format!( + "{} {} {}", + symbol_string, + op_str, + self.gen_attribute_value(attribute_value) + ) }, }; annotation_body From b07f4f86ac1f36395a80a432de6903988789f069 Mon Sep 17 00:00:00 2001 From: primata Date: Mon, 18 May 2026 17:12:38 -0300 Subject: [PATCH 2/9] passing tests --- Cargo.lock | 1 + third_party/move/move-compiler-v2/Cargo.toml | 1 + .../legacy-move-compiler/src/unit_test/mod.rs | 5 + third_party/move/move-compiler-v2/src/fuzz.rs | 1189 ++++++++++++++++- .../move/move-compiler-v2/src/fuzz_corpus.rs | 244 ++++ third_party/move/move-compiler-v2/src/lib.rs | 1 + .../move/move-compiler-v2/src/plan_builder.rs | 260 +++- .../move/move-compiler-v2/tests/testsuite.rs | 9 +- .../tests/unit_test/test/fuzz_constraints.exp | 45 +- .../tests/unit_test/test/fuzz_fixtures.exp | 10 + .../tests/unit_test/test/fuzz_fixtures.move | 12 + .../tests/unit_test/test/fuzz_implicit.exp | 21 +- .../test/fuzz_mix_assign_constraint.exp | 16 - .../tests/unit_test/test/fuzz_primitives.exp | 52 + .../tests/unit_test/test/fuzz_primitives.move | 29 + .../move/tools/move-unit-test/src/lib.rs | 114 +- .../tools/move-unit-test/src/test_runner.rs | 166 +++ 17 files changed, 2033 insertions(+), 142 deletions(-) create mode 100644 third_party/move/move-compiler-v2/src/fuzz_corpus.rs create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.move create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.move diff --git a/Cargo.lock b/Cargo.lock index 028956dba97..f1994c1a681 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11925,6 +11925,7 @@ dependencies = [ "num 0.4.1", "once_cell", "petgraph 0.6.5", + "serde", "serde_json", "walkdir", ] diff --git a/third_party/move/move-compiler-v2/Cargo.toml b/third_party/move/move-compiler-v2/Cargo.toml index b8c3a787afd..caf8de0645b 100644 --- a/third_party/move/move-compiler-v2/Cargo.toml +++ b/third_party/move/move-compiler-v2/Cargo.toml @@ -36,6 +36,7 @@ move-symbol-pool = { workspace = true } num = { workspace = true } once_cell = { workspace = true } petgraph = { workspace = true } +serde = { workspace = true } serde_json = { workspace = true } [dev-dependencies] diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs index e082ca973cd..1455676914d 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs @@ -33,6 +33,10 @@ pub struct TestPlan { // `NamedCompiledModule` for compiled modules with source, // `CompiledModule` for modules with bytecode only pub module_info: BTreeMap, + /// Opaque metadata that downstream runners may consult — e.g. the + /// `move-unit-test` runner stores `FuzzPlanMetadata` + fuzz source here + /// to enable shrinking/mutation. Legacy code does not introspect it. + pub runner_metadata: Option>, } #[derive(Debug, Clone)] @@ -125,6 +129,7 @@ impl TestPlan { files, module_tests, module_info, + runner_metadata: None, } } } diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs index 170087b136d..54f5dac49c2 100644 --- a/third_party/move/move-compiler-v2/src/fuzz.rs +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -3,15 +3,48 @@ //! Fuzz value generation for the `#[test]` attribute. //! -//! The compiler does not pick fuzz values itself. It collects the parameter -//! constraints (`a in `, `a != `, or absence-of-spec) into a -//! [`ParamSpec`] and asks a [`FuzzValueSource`] to materialize concrete values -//! for each parameter at plan-build time. The default source ([`NoFuzzSource`]) -//! errors loudly — install a real source via [`construct_test_plan`] to enable -//! fuzz expansion. +//! ## Design +//! +//! Modeled on Foundry's fuzz architecture (`crates/evm/fuzz/`): the compiler +//! does not pick fuzz values itself. It collects per-parameter constraints +//! (`a in `, `a != `, or absence-of-spec) into a [`ParamSpec`] +//! and asks a [`FuzzValueSource`] to materialize concrete values for each +//! parameter at plan-build time. +//! +//! Three sources of values are mixed when sampling a primitive parameter, in +//! the same spirit as Foundry's `UintStrategy` (`crates/evm/fuzz/src/strategies/uint.rs`): +//! +//! - **Random** — pseudo-random values drawn from the parameter type's full +//! width (default 50%). +//! - **Edge cases** — boundary values like `0`, `1`, `MAX`, `MAX-1`, `MAX/2` +//! to catch off-by-one bugs (default 10%). +//! - **Dictionary** — values mined from the surrounding Move program: named +//! address aliases and module-level constants of compatible primitive +//! types (default 40%). +//! +//! Domain (`a in ...`) and exclude (`a != ...`) sets filter the candidate +//! after generation; on a reject we redraw, capped at [`FUZZ_RETRIES`] times +//! the requested count to avoid pathological loops. +//! +//! The implementation is deterministic given the seed and intentionally +//! avoids `proptest` to keep the dependency surface small — the Foundry +//! analogue is `proptest` driven, but for a Move test runner the value +//! pipeline can be a plain seeded RNG since we do not (yet) need shrinking. + +use move_core_types::{ + account_address::AccountAddress, language_storage::ModuleId, u256, value::MoveValue, +}; +use move_model::{ + ast::{Address, AttributeValue, Value}, + model::GlobalEnv, + ty::{PrimitiveType, Type}, +}; +use num::{bigint::Sign, BigInt, ToPrimitive}; +use std::collections::BTreeMap; -use move_core_types::value::MoveValue; -use move_model::{ast::AttributeValue, ty::Type}; +// --------------------------------------------------------------------------- +// Public surface — unchanged from Phase 2 +// --------------------------------------------------------------------------- /// A single inclusive/half-open range. Both endpoints are model-AST literals /// because the compiler does not commit to a concrete representation until the @@ -49,26 +82,108 @@ pub enum ParamSpec { /// `a` not mentioned, or `a in ...` / `a != ...`. The fuzz source samples /// `n` values from `domain` (unrestricted when empty), subject to /// `exclude`. + Fuzz { domain: Domain, exclude: Domain }, +} + +// --------------------------------------------------------------------------- +// Plan metadata sidecar — Topic 3 / Topic 2 +// --------------------------------------------------------------------------- + +/// Per-argument origin for an expanded test case. The runner consults this to +/// decide whether shrinking and mutation are applicable to a failing case. +#[derive(Debug, Clone)] +pub enum ArgOrigin { + /// The argument came from a `Concrete` or `Matrix` spec; not shrinkable. + Fixed, + /// The argument was drawn by the fuzz source; eligible for shrink/mutate. Fuzz { + param_name: String, + ty: Type, domain: Domain, exclude: Domain, }, } +/// Map from `(module_id, expanded_test_name)` to per-argument origin. The +/// runner can look up an entry for a failing test to know which arguments to +/// shrink and which to keep fixed. +#[derive(Debug, Default, Clone)] +pub struct FuzzPlanMetadata { + pub entries: BTreeMap<(ModuleId, String), Vec>, +} + +impl FuzzPlanMetadata { + pub fn insert(&mut self, module_id: ModuleId, test_name: String, origins: Vec) { + self.entries.insert((module_id, test_name), origins); + } + + pub fn get(&self, module_id: &ModuleId, test_name: &str) -> Option<&Vec> { + // ModuleId isn't Hash for BTreeMap lookup with (&_, &str); rebuild key. + self.entries + .iter() + .find(|((m, n), _)| m == module_id && n == test_name) + .map(|(_, v)| v) + } +} + /// Plugged in by the unit-test entrypoint. The compiler never instantiates /// fuzz values itself; it only collects constraints. +/// +/// Three methods, two with default impls — implementers only need [`sample`]. +/// [`shrink`] gives counterexample minimization (Topic 3); [`mutate`] backs +/// the corpus-driven path (Topic 2). pub trait FuzzValueSource: Send + Sync { - /// Materialize `n` values of type `ty`, drawn from `domain` (unrestricted - /// when empty) and avoiding any value in `exclude`. `seed` is provided for - /// reproducibility. + /// Materialize `n` values of type `ty` for parameter `param_name`, drawn + /// from `domain` (unrestricted when empty) and avoiding any value in + /// `exclude`. `seed` is provided for reproducibility. + /// + /// `param_name` enables Foundry-style fixtures — sources can route + /// per-parameter using user-declared `FIXTURE_` constants. The + /// caller passes the parameter's display string so the trait doesn't + /// depend on a `SymbolPool`. fn sample( &self, ty: &Type, + param_name: &str, domain: &Domain, exclude: &Domain, n: usize, seed: u64, ) -> Result, String>; + + /// Produce a "smaller" candidate close to `current` for shrinking a failing + /// counterexample. Returns `None` when no further shrinking is possible — + /// the runner stops shrinking when this returns `None` or when no shrink + /// candidate still reproduces the failure. + /// + /// Default: no shrinking. Override for type-aware minimization. + fn shrink( + &self, + _ty: &Type, + _param_name: &str, + _current: &MoveValue, + _domain: &Domain, + _exclude: &Domain, + ) -> Option { + None + } + + /// Mutate `current` to a nearby value for corpus-driven exploration. + /// Returns `None` when no useful mutation is available. The mutated value + /// must still satisfy the original `domain` / `exclude`. + /// + /// Default: no mutation. Override when wiring corpus replay. + fn mutate( + &self, + _ty: &Type, + _param_name: &str, + _current: &MoveValue, + _domain: &Domain, + _exclude: &Domain, + _seed: u64, + ) -> Option { + None + } } /// Default source that produces no samples and reports a clear error. Plug a @@ -79,6 +194,7 @@ impl FuzzValueSource for NoFuzzSource { fn sample( &self, _ty: &Type, + _param_name: &str, _domain: &Domain, _exclude: &Domain, _n: usize, @@ -91,3 +207,1054 @@ impl FuzzValueSource for NoFuzzSource { ) } } + +// --------------------------------------------------------------------------- +// Configuration +// --------------------------------------------------------------------------- + +/// Tunables for [`DefaultFuzzSource`]. Defaults mirror Foundry's `[fuzz]` +/// section so users coming from EVM tooling find familiar knobs. +#[derive(Clone, Debug)] +pub struct FuzzConfig { + /// Number of samples drawn per implicit-fuzz parameter. + pub runs: usize, + /// Base RNG seed. Independent of the seed argument passed to + /// [`FuzzValueSource::sample`] — the two are mixed together so that the + /// same source can produce stable but parameter-distinct streams. + pub seed: u64, + /// Relative weight (0..=100) of dictionary draws against the random+edge + /// strategies. Mirrors Foundry's `dictionary_weight` (default 40). + pub dictionary_weight: u8, + /// Maximum number of retries (relative to `runs`) when domain/exclude + /// constraints reject candidate draws. + pub max_retry_multiplier: usize, +} + +impl Default for FuzzConfig { + fn default() -> Self { + Self { + runs: 16, + seed: 0, + dictionary_weight: 40, + max_retry_multiplier: 64, + } + } +} + +/// Foundry's `prop_oneof` carves up 100. We use the same shape so the +/// invariants travel: `random + edge + dictionary == 100`. +const EDGE_WEIGHT: u8 = 10; + +// --------------------------------------------------------------------------- +// Dictionary — Foundry analogue of `crates/evm/fuzz/src/strategies/state.rs` +// --------------------------------------------------------------------------- + +/// Typed pool of "interesting values" mined from the Move program. Roughly +/// analogous to Foundry's `FuzzDictionary`, but Move-shaped: instead of +/// account addresses + bytecode PUSH bytes + storage values from the EVM DB, +/// we collect named addresses + module-constant values from the model. +/// +/// `fixtures` holds per-parameter-name pools harvested from constants whose +/// name starts with `FIXTURE_` / `fixture_` (case-insensitive). The +/// remainder of the name, lowercased, is the parameter key. E.g. +/// `const FIXTURE_AMOUNT: u64 = 42;` populates `fixtures["amount"]`. +#[derive(Default, Debug)] +pub struct FuzzDictionary { + pub addresses: Vec, + pub uints: Vec, + pub bools: Vec, + pub fixtures: BTreeMap, +} + +/// Typed buckets for a single parameter's fixtures. +#[derive(Default, Debug, Clone)] +pub struct FixturePool { + pub addresses: Vec, + pub uints: Vec, + pub bools: Vec, +} + +impl FixturePool { + fn is_empty(&self) -> bool { + self.addresses.is_empty() && self.uints.is_empty() && self.bools.is_empty() + } +} + +const FIXTURE_PREFIX: &str = "fixture_"; + +impl FuzzDictionary { + /// Walk the [`GlobalEnv`] and harvest: + /// - every resolved named-address alias, + /// - every primitive-typed module constant, + /// - per-name fixture pools from `FIXTURE_` constants. + pub fn from_env(env: &GlobalEnv) -> Self { + let mut d = FuzzDictionary::default(); + + for addr in env.get_address_alias_map().values() { + d.addresses.push(*addr); + } + + for module in env.get_modules() { + for c in module.get_named_constants() { + let raw_name = env.symbol_pool().string(c.get_name()).to_string(); + let lowered = raw_name.to_lowercase(); + let value = c.get_value(); + + // Dictionary-wide insertion. + insert_value_into_buckets(env, &value, &mut d.addresses, &mut d.uints, &mut d.bools); + + // Fixture insertion when the name matches the prefix. + if let Some(rest) = lowered.strip_prefix(FIXTURE_PREFIX) { + if !rest.is_empty() { + let pool = d.fixtures.entry(rest.to_string()).or_default(); + insert_value_into_buckets( + env, + &value, + &mut pool.addresses, + &mut pool.uints, + &mut pool.bools, + ); + } + } + } + } + + d.addresses.sort_unstable(); + d.addresses.dedup(); + d.uints.sort(); + d.uints.dedup(); + d.bools.sort(); + d.bools.dedup(); + for pool in d.fixtures.values_mut() { + pool.addresses.sort_unstable(); + pool.addresses.dedup(); + pool.uints.sort(); + pool.uints.dedup(); + pool.bools.sort(); + pool.bools.dedup(); + } + d + } + + /// Lookup a fixture pool by lowercased parameter name. Returns `None` + /// when no fixtures were declared for that name. + pub fn fixture_for(&self, param_name_lowered: &str) -> Option<&FixturePool> { + self.fixtures + .get(param_name_lowered) + .filter(|p| !p.is_empty()) + } +} + +/// Slot a model AST `Value` into the appropriate typed bucket(s). Address +/// aliases that resolve are flattened to their numeric form. +fn insert_value_into_buckets( + env: &GlobalEnv, + value: &Value, + addrs: &mut Vec, + uints: &mut Vec, + bools: &mut Vec, +) { + match value { + Value::Address(Address::Numerical(a)) => addrs.push(*a), + Value::Address(Address::Symbolic(s)) => { + if let Some(a) = env.resolve_address_alias(*s) { + addrs.push(a); + } + }, + Value::Number(n) => uints.push(n.clone()), + Value::Bool(b) => bools.push(*b), + // Vector / ByteArray / Tuple are skipped for now — see Phase-4 design notes. + _ => {}, + } +} + +// --------------------------------------------------------------------------- +// DefaultFuzzSource — Foundry analogue of `FuzzedExecutor` +// --------------------------------------------------------------------------- + +/// Built-in fuzz value source: deterministic per `(config.seed, sample-seed)`, +/// honors Move primitive types, and mixes random + edge + dictionary draws. +pub struct DefaultFuzzSource { + pub config: FuzzConfig, + pub dictionary: FuzzDictionary, +} + +impl DefaultFuzzSource { + /// Construct a source whose dictionary is harvested from `env`. Use this + /// from the unit-test entrypoint — the dictionary is rebuilt per + /// compilation. + pub fn new(env: &GlobalEnv, config: FuzzConfig) -> Self { + Self { + dictionary: FuzzDictionary::from_env(env), + config, + } + } + + /// Construct a source with an empty dictionary. Useful in tests where the + /// dictionary pollution shouldn't matter. + pub fn with_empty_dictionary(config: FuzzConfig) -> Self { + Self { + dictionary: FuzzDictionary::default(), + config, + } + } +} + +impl FuzzValueSource for DefaultFuzzSource { + fn sample( + &self, + ty: &Type, + param_name: &str, + domain: &Domain, + exclude: &Domain, + n: usize, + seed: u64, + ) -> Result, String> { + let count = if n == 0 { self.config.runs } else { n }; + // Mix the configured base seed with the parameter-specific seed so that + // two parameters of the same type don't generate identical streams. + let mut rng = Rng(self.config.seed.wrapping_mul(0x9E3779B97F4A7C15).wrapping_add(seed)); + let fixture_pool = self.dictionary.fixture_for(¶m_name.to_lowercase()); + + match prim_kind(ty) { + Some(PrimKind::AddressLike(addr_like)) => sample_addresses( + &mut rng, + count, + addr_like, + domain, + exclude, + &self.dictionary, + fixture_pool, + ), + Some(PrimKind::Uint(width)) => sample_uints( + &mut rng, + count, + width, + domain, + exclude, + &self.dictionary, + fixture_pool, + self.config.dictionary_weight, + self.config.max_retry_multiplier, + ), + Some(PrimKind::Bool) => { + sample_bools(&mut rng, count, domain, exclude, fixture_pool) + }, + None => Err(format!( + "fuzz: cannot sample for parameter type `{:?}`; only address/signer, \ + uN (u8..u256), and bool are supported by the default source", + ty + )), + } + } + + fn shrink( + &self, + ty: &Type, + _param_name: &str, + current: &MoveValue, + domain: &Domain, + exclude: &Domain, + ) -> Option { + shrink_value(ty, current, domain, exclude) + } + + fn mutate( + &self, + ty: &Type, + _param_name: &str, + current: &MoveValue, + domain: &Domain, + exclude: &Domain, + seed: u64, + ) -> Option { + let mut rng = Rng(self.config.seed.wrapping_add(seed)); + mutate_value(&mut rng, ty, current, domain, exclude, &self.dictionary) + } +} + +// --------------------------------------------------------------------------- +// RNG — inline SplitMix64 +// --------------------------------------------------------------------------- + +/// Deterministic SplitMix64 — chosen instead of a `rand` dependency because +/// we only need uniform `u64` output, never a distribution from the `rand` +/// crate. Quality is sufficient for property-style fuzzing. +struct Rng(u64); + +impl Rng { + fn next_u64(&mut self) -> u64 { + self.0 = self.0.wrapping_add(0x9E3779B97F4A7C15); + let mut z = self.0; + z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9); + z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB); + z ^ (z >> 31) + } + + fn next_u128(&mut self) -> u128 { + let hi = self.next_u64() as u128; + let lo = self.next_u64() as u128; + (hi << 64) | lo + } + + fn pick<'a, T>(&mut self, xs: &'a [T]) -> Option<&'a T> { + if xs.is_empty() { + None + } else { + Some(&xs[(self.next_u64() as usize) % xs.len()]) + } + } +} + +// --------------------------------------------------------------------------- +// Type classification +// --------------------------------------------------------------------------- + +#[derive(Copy, Clone, Debug)] +enum PrimKind { + AddressLike(AddressLike), + Uint(UintWidth), + Bool, +} + +#[derive(Copy, Clone, Debug)] +enum AddressLike { + Address, + Signer, +} + +#[derive(Copy, Clone, Debug)] +enum UintWidth { + U8, + U16, + U32, + U64, + U128, + U256, +} + +fn prim_kind(ty: &Type) -> Option { + match ty { + Type::Primitive(p) => match p { + PrimitiveType::Address => Some(PrimKind::AddressLike(AddressLike::Address)), + PrimitiveType::Signer => Some(PrimKind::AddressLike(AddressLike::Signer)), + PrimitiveType::Bool => Some(PrimKind::Bool), + PrimitiveType::U8 => Some(PrimKind::Uint(UintWidth::U8)), + PrimitiveType::U16 => Some(PrimKind::Uint(UintWidth::U16)), + PrimitiveType::U32 => Some(PrimKind::Uint(UintWidth::U32)), + PrimitiveType::U64 => Some(PrimKind::Uint(UintWidth::U64)), + PrimitiveType::U128 => Some(PrimKind::Uint(UintWidth::U128)), + PrimitiveType::U256 => Some(PrimKind::Uint(UintWidth::U256)), + _ => None, + }, + Type::Reference(_, inner) => match &**inner { + Type::Primitive(PrimitiveType::Signer) => { + Some(PrimKind::AddressLike(AddressLike::Signer)) + }, + _ => None, + }, + _ => None, + } +} + +// --------------------------------------------------------------------------- +// Per-type samplers +// --------------------------------------------------------------------------- + +fn sample_bools( + rng: &mut Rng, + n: usize, + domain: &Domain, + exclude: &Domain, + fixtures: Option<&FixturePool>, +) -> Result, String> { + let dom_bools: Vec = domain.literals.iter().filter_map(extract_bool).collect(); + let exc_bools: Vec = exclude.literals.iter().filter_map(extract_bool).collect(); + let mut pool: Vec = if dom_bools.is_empty() { + vec![false, true] + } else { + dom_bools + }; + if let Some(f) = fixtures { + // Fixtures don't expand the bool universe but bias the picker — Foundry + // achieves this via weighting; we just duplicate them in the pool. + pool.extend(f.bools.iter().copied()); + } + let pool: Vec = pool.into_iter().filter(|b| !exc_bools.contains(b)).collect(); + if pool.is_empty() { + return Err("fuzz: bool domain is empty after exclusions".to_string()); + } + let mut out = Vec::with_capacity(n); + for _ in 0..n { + out.push(MoveValue::Bool(*rng.pick(&pool).unwrap())); + } + Ok(out) +} + +fn sample_addresses( + rng: &mut Rng, + n: usize, + kind: AddressLike, + domain: &Domain, + exclude: &Domain, + dict: &FuzzDictionary, + fixtures: Option<&FixturePool>, +) -> Result, String> { + let dom_addrs: Vec = domain + .literals + .iter() + .filter_map(extract_address) + .collect(); + let exc_addrs: Vec = exclude + .literals + .iter() + .filter_map(extract_address) + .collect(); + + // Ranges on addresses are interpreted as [lo, hi] address-byte intervals. + let dom_ranges = parse_address_ranges(&domain.ranges); + let exc_ranges = parse_address_ranges(&exclude.ranges); + let domain_active = !dom_addrs.is_empty() || !dom_ranges.is_empty(); + + let wrap = |addr: AccountAddress| match kind { + AddressLike::Address => MoveValue::Address(addr), + AddressLike::Signer => MoveValue::Signer(addr), + }; + let is_excluded = |addr: &AccountAddress| -> bool { + exc_addrs.contains(addr) + || exc_ranges + .iter() + .any(|(lo, hi, inc)| address_in_range(addr, lo, hi, *inc)) + }; + let in_domain = |addr: &AccountAddress| -> bool { + !domain_active + || dom_addrs.contains(addr) + || dom_ranges + .iter() + .any(|(lo, hi, inc)| address_in_range(addr, lo, hi, *inc)) + }; + + let mut out = Vec::with_capacity(n); + let mut tries = 0usize; + let cap = n.saturating_mul(64).max(1); + + // If the user explicitly listed addresses in the domain, prefer those — + // they are almost certainly the values they want exercised. + if !dom_addrs.is_empty() { + for a in &dom_addrs { + if !is_excluded(a) { + out.push(wrap(*a)); + if out.len() == n { + return Ok(out); + } + } + } + } + + // Same for fixtures: drain them upfront so the user always sees them. + if let Some(f) = fixtures { + for a in &f.addresses { + if in_domain(a) && !is_excluded(a) { + out.push(wrap(*a)); + if out.len() == n { + return Ok(out); + } + } + } + } + + while out.len() < n && tries < cap { + tries += 1; + let pick = rng.next_u64() % 100; + let candidate = if pick < u64::from(EDGE_WEIGHT) { + // Edge: well-known anchors. + let edges = [ + AccountAddress::ZERO, + AccountAddress::ONE, + AccountAddress::from_hex_literal("0x2").unwrap_or(AccountAddress::ONE), + ]; + *rng.pick(&edges).unwrap() + } else if !dict.addresses.is_empty() && pick < 100 { + // Dictionary, when available, otherwise random (handled below). + *rng.pick(&dict.addresses).unwrap() + } else { + let mut bytes = [0u8; AccountAddress::LENGTH]; + for chunk in bytes.chunks_exact_mut(8) { + chunk.copy_from_slice(&rng.next_u64().to_le_bytes()); + } + AccountAddress::new(bytes) + }; + let candidate = if dict.addresses.is_empty() && pick >= u64::from(EDGE_WEIGHT) && pick < 100 + { + // We fell into the "dictionary" branch but the dictionary is empty — + // synthesize a random address instead. + let mut bytes = [0u8; AccountAddress::LENGTH]; + for chunk in bytes.chunks_exact_mut(8) { + chunk.copy_from_slice(&rng.next_u64().to_le_bytes()); + } + AccountAddress::new(bytes) + } else { + candidate + }; + if !in_domain(&candidate) || is_excluded(&candidate) { + continue; + } + out.push(wrap(candidate)); + } + + if out.is_empty() { + return Err( + "fuzz: could not generate any address values satisfying the given constraints" + .to_string(), + ); + } + Ok(out) +} + +fn sample_uints( + rng: &mut Rng, + n: usize, + width: UintWidth, + domain: &Domain, + exclude: &Domain, + dict: &FuzzDictionary, + fixtures: Option<&FixturePool>, + dictionary_weight: u8, + max_retry_multiplier: usize, +) -> Result, String> { + let dom_lits: Vec = domain.literals.iter().filter_map(extract_bigint).collect(); + let exc_lits: Vec = exclude.literals.iter().filter_map(extract_bigint).collect(); + let dom_ranges = parse_int_ranges(&domain.ranges); + let exc_ranges = parse_int_ranges(&exclude.ranges); + let domain_active = !dom_lits.is_empty() || !dom_ranges.is_empty(); + let edges = uint_edges(width); + let modulus = uint_modulus(width); + + let is_excluded = |v: &BigInt| -> bool { + exc_lits.contains(v) + || exc_ranges + .iter() + .any(|(lo, hi, inc)| in_int_range(v, lo, hi, *inc)) + }; + let in_domain = |v: &BigInt| -> bool { + !domain_active + || dom_lits.contains(v) + || dom_ranges + .iter() + .any(|(lo, hi, inc)| in_int_range(v, lo, hi, *inc)) + }; + + let mut out = Vec::with_capacity(n); + + // Seed with explicit domain literals first. + for lit in &dom_lits { + if !is_excluded(lit) { + if let Some(v) = bigint_to_move_value(lit.clone(), width) { + out.push(v); + if out.len() == n { + return Ok(out); + } + } + } + } + + // Fixtures next: declared per-parameter values flow in before the + // randomized pool. + if let Some(f) = fixtures { + for v in &f.uints { + if in_domain(v) && !is_excluded(v) { + if let Some(mv) = bigint_to_move_value(v.clone(), width) { + out.push(mv); + if out.len() == n { + return Ok(out); + } + } + } + } + } + + let dictionary_weight = dictionary_weight.min(100); + let random_weight = 100u64.saturating_sub(u64::from(dictionary_weight) + u64::from(EDGE_WEIGHT)); + let edge_cutoff = u64::from(EDGE_WEIGHT); + let dict_cutoff = edge_cutoff + u64::from(dictionary_weight); + let _ = random_weight; // documentation; the random branch is the fall-through + + let mut tries = 0usize; + let cap = n.saturating_mul(max_retry_multiplier).max(1); + + while out.len() < n && tries < cap { + tries += 1; + let pick = rng.next_u64() % 100; + let candidate = if pick < edge_cutoff { + // Edge sample. If a domain range is active, draw an edge value + // bracketed against the active range. + if let Some((lo, hi, inc)) = rng.pick(&dom_ranges).cloned() { + let endpoints = [lo.clone(), hi.clone(), &lo + 1, if inc { hi } else { &hi - 1 }]; + rng.pick(&endpoints).cloned().unwrap_or_else(BigInt::default) + } else { + rng.pick(&edges).cloned().unwrap_or_else(BigInt::default) + } + } else if pick < dict_cutoff && !dict.uints.is_empty() { + rng.pick(&dict.uints).cloned().unwrap_or_else(BigInt::default) + } else if !dom_ranges.is_empty() { + // Random within an active domain range. + let (lo, hi, inc) = rng.pick(&dom_ranges).cloned().unwrap(); + sample_bigint_in_range(rng, &lo, &hi, inc) + } else { + BigInt::from(rng.next_u128() % modulus.clone().to_u128().unwrap_or(u128::MAX).max(1)) + }; + // Coerce candidate into the type's representable range. + let candidate = ((&candidate % &modulus) + &modulus) % &modulus; + if !in_domain(&candidate) || is_excluded(&candidate) { + continue; + } + if let Some(v) = bigint_to_move_value(candidate, width) { + out.push(v); + } + } + + if out.is_empty() { + return Err( + "fuzz: could not generate any uint values satisfying the given constraints" + .to_string(), + ); + } + Ok(out) +} + +// --------------------------------------------------------------------------- +// AttributeValue extraction & range parsing +// --------------------------------------------------------------------------- + +fn extract_bool(v: &AttributeValue) -> Option { + match v { + AttributeValue::Value(_, Value::Bool(b)) => Some(*b), + _ => None, + } +} + +fn extract_address(v: &AttributeValue) -> Option { + match v { + AttributeValue::Value(_, Value::Address(Address::Numerical(a))) => Some(*a), + _ => None, + } +} + +fn extract_bigint(v: &AttributeValue) -> Option { + match v { + AttributeValue::Value(_, Value::Number(n)) => Some(n.clone()), + AttributeValue::Value(_, Value::Address(Address::Numerical(a))) => { + Some(BigInt::from_bytes_be(Sign::Plus, a.as_ref())) + }, + _ => None, + } +} + +fn parse_int_ranges(ranges: &[RangeSpec]) -> Vec<(BigInt, BigInt, bool)> { + ranges + .iter() + .filter_map(|r| { + let lo = extract_bigint(&r.lo)?; + let hi = extract_bigint(&r.hi)?; + Some((lo, hi, r.inclusive_hi)) + }) + .collect() +} + +fn parse_address_ranges(ranges: &[RangeSpec]) -> Vec<(BigInt, BigInt, bool)> { + // Treat an address range identically to a numeric range over the + // 256-bit big-endian interpretation of the address bytes. + parse_int_ranges(ranges) +} + +fn in_int_range(v: &BigInt, lo: &BigInt, hi: &BigInt, inclusive_hi: bool) -> bool { + if v < lo { + return false; + } + if inclusive_hi { + v <= hi + } else { + v < hi + } +} + +fn address_in_range(addr: &AccountAddress, lo: &BigInt, hi: &BigInt, inclusive_hi: bool) -> bool { + let v = BigInt::from_bytes_be(Sign::Plus, addr.as_ref()); + in_int_range(&v, lo, hi, inclusive_hi) +} + +// --------------------------------------------------------------------------- +// Numeric helpers +// --------------------------------------------------------------------------- + +fn uint_modulus(width: UintWidth) -> BigInt { + match width { + UintWidth::U8 => BigInt::from(1u64) << 8, + UintWidth::U16 => BigInt::from(1u64) << 16, + UintWidth::U32 => BigInt::from(1u64) << 32, + UintWidth::U64 => BigInt::from(1u128) << 64, + UintWidth::U128 => BigInt::from(1u128) << 127 << 1, + UintWidth::U256 => BigInt::from(1u128) << 128 << 128, + } +} + +fn uint_edges(width: UintWidth) -> Vec { + let m = uint_modulus(width); + let max = &m - 1; + let half: BigInt = &m / 2; + vec![ + BigInt::from(0), + BigInt::from(1), + BigInt::from(2), + &half - 1, + half.clone(), + &half + 1, + &max - 1, + max, + ] +} + +fn sample_bigint_in_range(rng: &mut Rng, lo: &BigInt, hi: &BigInt, inclusive_hi: bool) -> BigInt { + let exclusive_hi = if inclusive_hi { + hi + BigInt::from(1) + } else { + hi.clone() + }; + let span = &exclusive_hi - lo; + if span <= BigInt::from(0) { + return lo.clone(); + } + // Generate a random BigInt 0..span and offset by lo. We approximate with + // a fixed pool of u64 limbs sufficient for any Move primitive (u256 fits + // in 4 limbs); a small modulo bias is acceptable for fuzz purposes. + let mut limbs = Vec::with_capacity(4); + for _ in 0..4 { + limbs.push(rng.next_u64()); + } + let raw = BigInt::from_slice(Sign::Plus, &limbs_to_u32(&limbs)); + lo + raw % span +} + +fn limbs_to_u32(u64s: &[u64]) -> Vec { + let mut out = Vec::with_capacity(u64s.len() * 2); + for n in u64s { + out.push((*n & 0xFFFF_FFFF) as u32); + out.push((*n >> 32) as u32); + } + out +} + +// --------------------------------------------------------------------------- +// Shrinking — Topic 3 +// --------------------------------------------------------------------------- + +/// Produce one shrink candidate closer to "minimal" than `current`. Order is +/// deterministic: zero first, then halving, then decrement. The runner calls +/// this in a loop and stops when the shrunk value either passes the test or +/// when this returns `None`. +fn shrink_value( + ty: &Type, + current: &MoveValue, + domain: &Domain, + exclude: &Domain, +) -> Option { + let kind = prim_kind(ty)?; + let dom_lits; + let dom_ranges; + let exc_lits; + let exc_ranges; + let domain_active; + + match kind { + PrimKind::Uint(width) => { + dom_lits = domain + .literals + .iter() + .filter_map(extract_bigint) + .collect::>(); + dom_ranges = parse_int_ranges(&domain.ranges); + exc_lits = exclude + .literals + .iter() + .filter_map(extract_bigint) + .collect::>(); + exc_ranges = parse_int_ranges(&exclude.ranges); + domain_active = !dom_lits.is_empty() || !dom_ranges.is_empty(); + let cur = move_value_to_bigint(current)?; + // Build candidates in order from "most aggressive shrink" to least. + let candidates: Vec = vec![ + BigInt::from(0), + &cur / 2, + &cur - 1, + ]; + for c in candidates { + if c == cur { + continue; + } + if c < BigInt::from(0) { + continue; + } + let in_dom = !domain_active + || dom_lits.contains(&c) + || dom_ranges + .iter() + .any(|(lo, hi, inc)| in_int_range(&c, lo, hi, *inc)); + let excluded = exc_lits.contains(&c) + || exc_ranges + .iter() + .any(|(lo, hi, inc)| in_int_range(&c, lo, hi, *inc)); + if in_dom && !excluded { + return bigint_to_move_value(c, width); + } + } + None + }, + PrimKind::Bool => match current { + MoveValue::Bool(true) => { + let exc: Vec = exclude.literals.iter().filter_map(extract_bool).collect(); + let dom: Vec = domain.literals.iter().filter_map(extract_bool).collect(); + let domain_active = !dom.is_empty(); + let in_dom = !domain_active || dom.contains(&false); + if in_dom && !exc.contains(&false) { + Some(MoveValue::Bool(false)) + } else { + None + } + }, + _ => None, + }, + PrimKind::AddressLike(kind) => { + let cur = match current { + MoveValue::Address(a) | MoveValue::Signer(a) => *a, + _ => return None, + }; + let dom_addrs: Vec = domain + .literals + .iter() + .filter_map(extract_address) + .collect(); + let exc_addrs: Vec = exclude + .literals + .iter() + .filter_map(extract_address) + .collect(); + let dom_ranges = parse_address_ranges(&domain.ranges); + let exc_ranges = parse_address_ranges(&exclude.ranges); + let domain_active = !dom_addrs.is_empty() || !dom_ranges.is_empty(); + // Address "shrink" candidates: 0x0, 0x1, and any domain-literal that's "smaller". + let mut candidates = vec![AccountAddress::ZERO, AccountAddress::ONE]; + for a in &dom_addrs { + if a.as_ref() < cur.as_ref() { + candidates.push(*a); + } + } + for c in candidates { + if c == cur { + continue; + } + let in_dom = !domain_active + || dom_addrs.contains(&c) + || dom_ranges + .iter() + .any(|(lo, hi, inc)| address_in_range(&c, lo, hi, *inc)); + let excluded = exc_addrs.contains(&c) + || exc_ranges + .iter() + .any(|(lo, hi, inc)| address_in_range(&c, lo, hi, *inc)); + if in_dom && !excluded { + return Some(match kind { + AddressLike::Address => MoveValue::Address(c), + AddressLike::Signer => MoveValue::Signer(c), + }); + } + } + None + }, + } +} + +fn move_value_to_bigint(v: &MoveValue) -> Option { + match v { + MoveValue::U8(x) => Some(BigInt::from(*x)), + MoveValue::U16(x) => Some(BigInt::from(*x)), + MoveValue::U32(x) => Some(BigInt::from(*x)), + MoveValue::U64(x) => Some(BigInt::from(*x)), + MoveValue::U128(x) => Some(BigInt::from(*x)), + MoveValue::U256(x) => { + // u256::U256 → big-endian bytes → BigInt + let bytes_le = x.to_le_bytes(); + let mut bytes_be = bytes_le; + bytes_be.reverse(); + Some(BigInt::from_bytes_be(Sign::Plus, &bytes_be)) + }, + _ => None, + } +} + +// --------------------------------------------------------------------------- +// Mutation — Topic 2 (corpus-driven exploration) +// --------------------------------------------------------------------------- + +/// Produce one mutated value near `current`. Mirrors Foundry's +/// `mutate_param_value` at `crates/evm/fuzz/src/strategies/param.rs`: bit +/// flips on the low byte, increment/decrement, swap from the dictionary, +/// or pick a domain literal. Result must satisfy the original constraints. +fn mutate_value( + rng: &mut Rng, + ty: &Type, + current: &MoveValue, + domain: &Domain, + exclude: &Domain, + dict: &FuzzDictionary, +) -> Option { + let kind = prim_kind(ty)?; + match kind { + PrimKind::Uint(width) => { + let cur = move_value_to_bigint(current)?; + let m = uint_modulus(width); + let choice = rng.next_u64() % 5; + let cand = match choice { + 0 => &cur + 1, + 1 => (&cur + &m - 1) % &m, // decrement with wraparound + 2 => cur.clone() ^ BigInt::from(rng.next_u64() & 0xFF), + 3 => { + if let Some(d) = rng.pick(&dict.uints) { + d.clone() + } else { + &cur ^ BigInt::from(1) + } + }, + _ => { + let lits: Vec = + domain.literals.iter().filter_map(extract_bigint).collect(); + rng.pick(&lits).cloned().unwrap_or(cur.clone()) + }, + }; + let cand = ((&cand % &m) + &m) % &m; + if cand == cur { + return None; + } + // Domain/exclude filter. + let dom_lits: Vec = + domain.literals.iter().filter_map(extract_bigint).collect(); + let dom_ranges = parse_int_ranges(&domain.ranges); + let exc_lits: Vec = + exclude.literals.iter().filter_map(extract_bigint).collect(); + let exc_ranges = parse_int_ranges(&exclude.ranges); + let active = !dom_lits.is_empty() || !dom_ranges.is_empty(); + let in_dom = !active + || dom_lits.contains(&cand) + || dom_ranges + .iter() + .any(|(lo, hi, inc)| in_int_range(&cand, lo, hi, *inc)); + let excluded = exc_lits.contains(&cand) + || exc_ranges + .iter() + .any(|(lo, hi, inc)| in_int_range(&cand, lo, hi, *inc)); + if in_dom && !excluded { + bigint_to_move_value(cand, width) + } else { + None + } + }, + PrimKind::Bool => match current { + MoveValue::Bool(b) => { + let flipped = !*b; + let exc: Vec = + exclude.literals.iter().filter_map(extract_bool).collect(); + let dom: Vec = domain.literals.iter().filter_map(extract_bool).collect(); + let active = !dom.is_empty(); + let in_dom = !active || dom.contains(&flipped); + if in_dom && !exc.contains(&flipped) { + Some(MoveValue::Bool(flipped)) + } else { + None + } + }, + _ => None, + }, + PrimKind::AddressLike(kind) => { + let cur = match current { + MoveValue::Address(a) | MoveValue::Signer(a) => *a, + _ => return None, + }; + let choice = rng.next_u64() % 3; + let cand = match choice { + 0 => *rng.pick(&dict.addresses).unwrap_or(&AccountAddress::ZERO), + 1 => { + // Bit flip in the low byte. + let mut bytes = cur.into_bytes(); + let last = bytes.len() - 1; + bytes[last] ^= 1; + AccountAddress::new(bytes) + }, + _ => { + let lits: Vec = domain + .literals + .iter() + .filter_map(extract_address) + .collect(); + *rng.pick(&lits).unwrap_or(&cur) + }, + }; + if cand == cur { + return None; + } + let dom_addrs: Vec = domain + .literals + .iter() + .filter_map(extract_address) + .collect(); + let exc_addrs: Vec = exclude + .literals + .iter() + .filter_map(extract_address) + .collect(); + let dom_ranges = parse_address_ranges(&domain.ranges); + let exc_ranges = parse_address_ranges(&exclude.ranges); + let active = !dom_addrs.is_empty() || !dom_ranges.is_empty(); + let in_dom = !active + || dom_addrs.contains(&cand) + || dom_ranges + .iter() + .any(|(lo, hi, inc)| address_in_range(&cand, lo, hi, *inc)); + let excluded = exc_addrs.contains(&cand) + || exc_ranges + .iter() + .any(|(lo, hi, inc)| address_in_range(&cand, lo, hi, *inc)); + if in_dom && !excluded { + Some(match kind { + AddressLike::Address => MoveValue::Address(cand), + AddressLike::Signer => MoveValue::Signer(cand), + }) + } else { + None + } + }, + } +} + +fn bigint_to_move_value(n: BigInt, width: UintWidth) -> Option { + let m = uint_modulus(width); + let n = ((&n % &m) + &m) % &m; + match width { + UintWidth::U8 => n.to_u64().map(|x| MoveValue::U8(x as u8)), + UintWidth::U16 => n.to_u64().map(|x| MoveValue::U16(x as u16)), + UintWidth::U32 => n.to_u64().map(|x| MoveValue::U32(x as u32)), + UintWidth::U64 => n.to_u64().map(MoveValue::U64), + UintWidth::U128 => n.to_u128().map(MoveValue::U128), + UintWidth::U256 => { + // Take the low 32 bytes (big-endian) of `n`. + let (_sign, bytes_be) = n.to_bytes_be(); + let mut buf = [0u8; 32]; + let off = 32usize.saturating_sub(bytes_be.len()); + buf[off..].copy_from_slice(&bytes_be[bytes_be.len().saturating_sub(32)..]); + // u256::U256 has a `from_be_bytes`/`from_le_bytes` API; use whichever is present. + Some(MoveValue::U256(u256::U256::from_le_bytes(&{ + let mut le = buf; + le.reverse(); + le + }))) + }, + } +} diff --git a/third_party/move/move-compiler-v2/src/fuzz_corpus.rs b/third_party/move/move-compiler-v2/src/fuzz_corpus.rs new file mode 100644 index 00000000000..b200920dfa4 --- /dev/null +++ b/third_party/move/move-compiler-v2/src/fuzz_corpus.rs @@ -0,0 +1,244 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +//! On-disk fuzz corpus. +//! +//! Layout — one BCS-encoded file per `(module, test)`: +//! +//! ```text +//! /failures/...bcs Vec> +//! /seeds/...bcs Vec> +//! ``` +//! +//! - `failures/` — argument vectors that previously caused this test to fail. +//! Always replayed first on the next run, so a regression never silently +//! disappears. +//! - `seeds/` — argument vectors deemed interesting (e.g. mutated from +//! prior runs). Replayed if `--fuzz-corpus-replay-seeds` is set. +//! +//! This is intentionally schema-thin: only the `Vec` arguments +//! are persisted, not the full `ArgOrigin` metadata. Replayed entries run as +//! `Fixed`-origin TestCases — they reproduce the failing input but are not +//! eligible for further shrinking. The user can still get shrinking on the +//! fresh fuzz draws that run alongside them. + +use anyhow::{anyhow, Context, Result}; +use move_core_types::{ + account_address::AccountAddress, language_storage::ModuleId, u256, value::MoveValue, +}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::BTreeSet, + fs, + path::{Path, PathBuf}, +}; + +/// Wire format for corpus entries. `MoveValue` cannot be (de)serialized +/// without a `MoveTypeLayout`, so we round-trip through this proxy that +/// covers exactly the primitive set the default fuzz source produces. +#[derive(Debug, Clone, Serialize, Deserialize)] +enum WireValue { + U8(u8), + U16(u16), + U32(u32), + U64(u64), + U128(u128), + U256([u8; 32]), + Bool(bool), + Address([u8; AccountAddress::LENGTH]), + Signer([u8; AccountAddress::LENGTH]), +} + +impl WireValue { + fn from_move(value: &MoveValue) -> Result { + Ok(match value { + MoveValue::U8(x) => WireValue::U8(*x), + MoveValue::U16(x) => WireValue::U16(*x), + MoveValue::U32(x) => WireValue::U32(*x), + MoveValue::U64(x) => WireValue::U64(*x), + MoveValue::U128(x) => WireValue::U128(*x), + MoveValue::U256(x) => WireValue::U256(x.to_le_bytes()), + MoveValue::Bool(b) => WireValue::Bool(*b), + MoveValue::Address(a) => WireValue::Address(a.into_bytes()), + MoveValue::Signer(a) => WireValue::Signer(a.into_bytes()), + other => { + return Err(anyhow!( + "corpus: unsupported MoveValue variant `{:?}` (only primitives are serialized)", + other + )); + }, + }) + } + + fn into_move(self) -> MoveValue { + match self { + WireValue::U8(x) => MoveValue::U8(x), + WireValue::U16(x) => MoveValue::U16(x), + WireValue::U32(x) => MoveValue::U32(x), + WireValue::U64(x) => MoveValue::U64(x), + WireValue::U128(x) => MoveValue::U128(x), + WireValue::U256(bytes) => MoveValue::U256(u256::U256::from_le_bytes(&bytes)), + WireValue::Bool(b) => MoveValue::Bool(b), + WireValue::Address(a) => MoveValue::Address(AccountAddress::new(a)), + WireValue::Signer(a) => MoveValue::Signer(AccountAddress::new(a)), + } + } +} + +fn to_wire(args: &[MoveValue]) -> Result> { + args.iter().map(WireValue::from_move).collect() +} + +fn from_wire(args: Vec) -> Vec { + args.into_iter().map(WireValue::into_move).collect() +} + +/// Subdirectory holding regression cases that previously failed. +const FAILURES_SUBDIR: &str = "failures"; + +/// Subdirectory holding mutated/seeded interesting cases. +const SEEDS_SUBDIR: &str = "seeds"; + +/// Compose the on-disk filename for one `(module, test)` pair. +fn corpus_filename(module_id: &ModuleId, test_name: &str) -> String { + // Test names may contain `[`/`]`/`=`/`,` from expansion suffixes; replace + // them with `_` so filenames stay portable. + let sanitized: String = test_name + .chars() + .map(|c| match c { + 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' | '-' | '.' => c, + _ => '_', + }) + .collect(); + format!( + "{}.{}.{}.bcs", + module_id.address().short_str_lossless(), + module_id.name().as_str(), + sanitized + ) +} + +fn read_corpus_file(path: &Path) -> Result>> { + let bytes = fs::read(path).with_context(|| format!("reading {}", path.display()))?; + let wire: Vec> = bcs::from_bytes(&bytes) + .with_context(|| format!("decoding {}", path.display()))?; + Ok(wire.into_iter().map(from_wire).collect()) +} + +fn write_corpus_file(path: &Path, cases: &[Vec]) -> Result<()> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent) + .with_context(|| format!("creating {}", parent.display()))?; + } + let wire: Vec> = cases + .iter() + .map(|c| to_wire(c)) + .collect::>()?; + let bytes = bcs::to_bytes(&wire).context("encoding corpus")?; + fs::write(path, bytes).with_context(|| format!("writing {}", path.display()))?; + Ok(()) +} + +/// Load failure-regression entries for `(module, test)`. Returns an empty +/// vector when no file exists. +pub fn load_failures( + corpus_dir: &Path, + module_id: &ModuleId, + test_name: &str, +) -> Result>> { + let path = corpus_dir + .join(FAILURES_SUBDIR) + .join(corpus_filename(module_id, test_name)); + if !path.exists() { + return Ok(Vec::new()); + } + read_corpus_file(&path) +} + +/// Load seed entries for `(module, test)`. Returns an empty vector when no +/// file exists. +pub fn load_seeds( + corpus_dir: &Path, + module_id: &ModuleId, + test_name: &str, +) -> Result>> { + let path = corpus_dir + .join(SEEDS_SUBDIR) + .join(corpus_filename(module_id, test_name)); + if !path.exists() { + return Ok(Vec::new()); + } + read_corpus_file(&path) +} + +/// Append `args` to the failures file for `(module, test)`, de-duping against +/// the existing entries. Idempotent. +pub fn append_failure( + corpus_dir: &Path, + module_id: &ModuleId, + test_name: &str, + args: &[MoveValue], +) -> Result<()> { + let path = corpus_dir + .join(FAILURES_SUBDIR) + .join(corpus_filename(module_id, test_name)); + let mut existing = if path.exists() { + read_corpus_file(&path)? + } else { + Vec::new() + }; + let mut seen: BTreeSet> = existing + .iter() + .filter_map(|e| to_wire(e).ok().and_then(|w| bcs::to_bytes(&w).ok())) + .collect(); + let key = to_wire(args).and_then(|w| bcs::to_bytes(&w).map_err(Into::into)); + let key = match key { + Ok(k) => k, + Err(_) => return Ok(()), // unsupported variant; silently skip + }; + if seen.insert(key) { + existing.push(args.to_vec()); + write_corpus_file(&path, &existing)?; + } + Ok(()) +} + +/// Append `args` to the seeds file for `(module, test)`. +pub fn append_seed( + corpus_dir: &Path, + module_id: &ModuleId, + test_name: &str, + args: &[MoveValue], +) -> Result<()> { + let path = corpus_dir + .join(SEEDS_SUBDIR) + .join(corpus_filename(module_id, test_name)); + let mut existing = if path.exists() { + read_corpus_file(&path)? + } else { + Vec::new() + }; + let mut seen: BTreeSet> = existing + .iter() + .filter_map(|e| to_wire(e).ok().and_then(|w| bcs::to_bytes(&w).ok())) + .collect(); + let key = to_wire(args).and_then(|w| bcs::to_bytes(&w).map_err(Into::into)); + let key = match key { + Ok(k) => k, + Err(_) => return Ok(()), + }; + if seen.insert(key) { + existing.push(args.to_vec()); + write_corpus_file(&path, &existing)?; + } + Ok(()) +} + +/// Standard path resolution. Pass through to expose the layout. +pub fn failures_dir(corpus_dir: &Path) -> PathBuf { + corpus_dir.join(FAILURES_SUBDIR) +} + +pub fn seeds_dir(corpus_dir: &Path) -> PathBuf { + corpus_dir.join(SEEDS_SUBDIR) +} diff --git a/third_party/move/move-compiler-v2/src/lib.rs b/third_party/move/move-compiler-v2/src/lib.rs index 12978646f83..918688bba99 100644 --- a/third_party/move/move-compiler-v2/src/lib.rs +++ b/third_party/move/move-compiler-v2/src/lib.rs @@ -9,6 +9,7 @@ mod experiments; pub mod external_checks; mod file_format_generator; pub mod fuzz; +pub mod fuzz_corpus; pub mod lint_common; pub mod logging; pub mod options; diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index 8b9702d7940..2d8a931980c 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -12,7 +12,9 @@ //! success. use crate::{ - fuzz::{Domain, FuzzValueSource, NoFuzzSource, ParamSpec, RangeSpec}, + fuzz::{ + ArgOrigin, Domain, FuzzPlanMetadata, FuzzValueSource, NoFuzzSource, ParamSpec, RangeSpec, + }, options::Options, }; use codespan_reporting::diagnostic::Severity; @@ -44,6 +46,15 @@ const MAX_FUZZ_CASES: usize = 1024; // Test Plan Building //*************************************************************************** +/// Output of plan-building: the test plans plus a sidecar map of fuzz +/// metadata keyed by `(ModuleId, expanded_test_name)`. The metadata is what +/// lets the runner shrink failing fuzz cases and mutate corpus entries. +#[derive(Debug, Clone)] +pub struct TestPlanBuild { + pub plans: Vec, + pub fuzz_metadata: FuzzPlanMetadata, +} + // Constructs a test plan for each module in `env.target`. This also validates the structure of the // attributes as the test plan is constructed. pub fn construct_test_plan( @@ -51,37 +62,44 @@ pub fn construct_test_plan( package_filter: Option, ) -> Option> { construct_test_plan_with_fuzz_source(env, package_filter, &NoFuzzSource) + .map(|build| build.plans) } /// Like [`construct_test_plan`], but the caller can supply a [`FuzzValueSource`] to materialize -/// values for implicit-fuzz or `in`/`!=` constrained parameters. +/// values for implicit-fuzz or `in`/`!=` constrained parameters. Returns a [`TestPlanBuild`] +/// carrying both the per-module test plans and the [`FuzzPlanMetadata`] sidecar. pub fn construct_test_plan_with_fuzz_source( env: &GlobalEnv, package_filter: Option, fuzz_source: &dyn FuzzValueSource, -) -> Option> { +) -> Option { let options = env.get_extension::().expect("options"); if !options.compile_test_code { return None; } - Some( - env.get_modules() - .filter_map(|module| { - if module.is_primary_target() { - construct_module_test_plan(env, package_filter, fuzz_source, module) - } else { - None - } - }) - .collect(), - ) + let mut metadata = FuzzPlanMetadata::default(); + let plans: Vec = env + .get_modules() + .filter_map(|module| { + if module.is_primary_target() { + construct_module_test_plan(env, package_filter, fuzz_source, &mut metadata, module) + } else { + None + } + }) + .collect(); + Some(TestPlanBuild { + plans, + fuzz_metadata: metadata, + }) } fn construct_module_test_plan( env: &GlobalEnv, _package_filter: Option, fuzz_source: &dyn FuzzValueSource, + metadata: &mut FuzzPlanMetadata, module: ModuleEnv, ) -> Option { // TODO (#12885): what is a package? Do we need this code? @@ -90,11 +108,29 @@ fn construct_module_test_plan( // } let current_module = module.get_name(); - let tests: BTreeMap<_, _> = module + let module_id_for_meta = module.get_identifier().map(|name| { + let addr_bytes = match current_module.addr() { + Address::Numerical(num_addr) => Some(*num_addr), + Address::Symbolic(sym) => env.resolve_address_alias(*sym), + }; + (addr_bytes, name) + }); + + let expanded: Vec = module .get_functions() - .flat_map(|func| build_test_info(env, current_module, fuzz_source, func).into_iter()) - .map(|test_case| (test_case.test_name.clone(), test_case)) + .flat_map(|func| build_test_info(env, current_module, fuzz_source, func)) .collect(); + let mut tests: BTreeMap = BTreeMap::new(); + for ex in expanded { + if let Some((Some(addr), name)) = module_id_for_meta.as_ref() { + metadata.insert( + ModuleId::new(*addr, name.clone()), + ex.case.test_name.clone(), + ex.origins, + ); + } + tests.insert(ex.case.test_name.clone(), ex.case); + } let module_id = module.get_identifier(); if tests.is_empty() { @@ -123,12 +159,19 @@ fn construct_module_test_plan( } } +/// One expanded `#[test]` case: a `TestCase` ready for the runner plus the +/// per-argument origin that lets the runner shrink/mutate when appropriate. +pub struct ExpandedCase { + pub case: TestCase, + pub origins: Vec, +} + fn build_test_info( env: &GlobalEnv, current_module: &ModuleName, fuzz_source: &dyn FuzzValueSource, function: FunctionEnv, -) -> Vec { +) -> Vec { let fn_name_str = function.get_name_str(); let fn_id_loc = function.get_id_loc(); @@ -183,13 +226,25 @@ fn build_test_info( let parameters: Vec<_> = function.get_parameters_ref().iter().cloned().collect(); - // For each parameter, materialize one dimension of MoveValues. + // We separate deterministic dimensions (Concrete/Matrix) from fuzz dimensions so that + // explicit matrices Cartesian-multiply but independent fuzz draws *zip* together: with + // `#[test(a, b)]` the user expects N runs total, each binding `a[i]` and `b[i]`, not + // N² combinations. Matches Foundry's `[fuzz] runs = N` semantics. let mut had_error = false; let mut had_fuzz = false; - let mut dimensions: Vec<(Symbol, Vec)> = Vec::with_capacity(parameters.len()); + enum Dim { + Det(Vec), + Fuzz { + values: Vec, + param_name: String, + ty: Type, + domain: Domain, + exclude: Domain, + }, + } + let mut dims: Vec<(Symbol, Dim)> = Vec::with_capacity(parameters.len()); for param in ¶meters { let Parameter(var, ty, var_loc) = param; - // Synthesize an implicit-fuzz spec when no spec was given for this param. let owned_default; let spec_ref = match specs.get(var) { Some(s) => s, @@ -201,6 +256,8 @@ fn build_test_info( &owned_default }, }; + let is_fuzz = matches!(spec_ref, ParamSpec::Fuzz { .. }); + let param_name = env.symbol_pool().string(*var); match materialize_param_values( env, fuzz_source, @@ -208,13 +265,26 @@ fn build_test_info( &test_attribute_loc, var_loc, ty, + param_name.as_str(), spec_ref, ) { Some(values) => { - if matches!(spec_ref, ParamSpec::Fuzz { .. }) { + if is_fuzz { had_fuzz = true; + let (domain, exclude) = match spec_ref { + ParamSpec::Fuzz { domain, exclude } => (domain.clone(), exclude.clone()), + _ => unreachable!(), + }; + dims.push((*var, Dim::Fuzz { + values, + param_name: param_name.to_string(), + ty: ty.clone(), + domain, + exclude, + })); + } else { + dims.push((*var, Dim::Det(values))); } - dimensions.push((*var, values)); }, None => had_error = true, } @@ -229,18 +299,30 @@ fn build_test_info( Some(abort_attribute) => parse_failure_attribute(env, current_module, abort_attribute), }; - // Cartesian product across all parameter dimensions. - let total: usize = dimensions + // Cartesian over deterministic dimensions; zip across fuzz dimensions. + let det_product: usize = dims .iter() - .map(|(_, vs)| vs.len()) + .filter_map(|(_, d)| if let Dim::Det(vs) = d { Some(vs.len()) } else { None }) .product::() .max(1); + let fuzz_runs: usize = dims + .iter() + .filter_map(|(_, d)| { + if let Dim::Fuzz { values, .. } = d { + Some(values.len()) + } else { + None + } + }) + .min() + .unwrap_or(1); + let total = det_product.saturating_mul(fuzz_runs); if total > MAX_FUZZ_CASES { env.error( &fn_id_loc, &format!( "#[test] expansion would produce {} cases (cap: {}). Narrow the matrix, fuzz \ - domain, or `--fuzz-iterations`.", + domain, or `--fuzz-runs`.", total, MAX_FUZZ_CASES ), ); @@ -260,55 +342,94 @@ fn build_test_info( ); } - if dimensions.is_empty() { + if dims.is_empty() { // Zero-arg function: a single case with no arguments and the bare function name. - return vec![TestCase { - test_name: fn_name_str.to_string(), - arguments: Vec::new(), - expected_failure, + return vec![ExpandedCase { + case: TestCase { + test_name: fn_name_str.to_string(), + arguments: Vec::new(), + expected_failure, + }, + origins: Vec::new(), }]; } - // If every dimension has exactly one value, emit a single TestCase with the bare function - // name (preserves existing test-name behavior for non-expanded #[test] functions). - let is_single = dimensions.iter().all(|(_, vs)| vs.len() == 1); + let is_single = total == 1; + + // Iterate: for each Cartesian point of the deterministic dims, run `fuzz_runs` zipped + // draws over the fuzz dims. When `had_fuzz` is false this collapses to plain Cartesian. + let det_lens: Vec = dims + .iter() + .map(|(_, d)| match d { + Dim::Det(vs) => vs.len(), + Dim::Fuzz { .. } => 1, // placeholder; we drive fuzz with `fuzz_iter` + }) + .collect(); let mut cases = Vec::with_capacity(total); - let mut indices = vec![0usize; dimensions.len()]; + let mut det_indices = vec![0usize; dims.len()]; loop { - let mut arguments = Vec::with_capacity(dimensions.len()); - let mut suffix_parts = Vec::with_capacity(dimensions.len()); - for (i, (var, vs)) in dimensions.iter().enumerate() { - let v = &vs[indices[i]]; - arguments.push(v.clone()); - suffix_parts.push(format!( - "{}={}", - var.display(env.symbol_pool()), - format_move_value(v) - )); + for fuzz_iter in 0..fuzz_runs { + let mut arguments = Vec::with_capacity(dims.len()); + let mut suffix_parts = Vec::with_capacity(dims.len()); + let mut origins = Vec::with_capacity(dims.len()); + for (i, (var, d)) in dims.iter().enumerate() { + let v = match d { + Dim::Det(vs) => &vs[det_indices[i]], + Dim::Fuzz { values, .. } => &values[fuzz_iter % values.len()], + }; + arguments.push(v.clone()); + suffix_parts.push(format!( + "{}={}", + var.display(env.symbol_pool()), + format_move_value(v) + )); + origins.push(match d { + Dim::Det(_) => ArgOrigin::Fixed, + Dim::Fuzz { + param_name, + ty, + domain, + exclude, + .. + } => ArgOrigin::Fuzz { + param_name: param_name.clone(), + ty: ty.clone(), + domain: domain.clone(), + exclude: exclude.clone(), + }, + }); + } + let test_name = if is_single { + fn_name_str.to_string() + } else { + format!("{}[{}]", fn_name_str, suffix_parts.join(",")) + }; + cases.push(ExpandedCase { + case: TestCase { + test_name, + arguments, + expected_failure: expected_failure.clone(), + }, + origins, + }); } - let test_name = if is_single { - fn_name_str.to_string() - } else { - format!("{}[{}]", fn_name_str, suffix_parts.join(",")) - }; - cases.push(TestCase { - test_name, - arguments, - expected_failure: expected_failure.clone(), - }); - // Advance odometer. - let mut idx = dimensions.len(); + // Advance odometer across deterministic dims only — fuzz dims are zipped + // by `fuzz_iter` above. + let mut idx = dims.len(); loop { if idx == 0 { return cases; } idx -= 1; - indices[idx] += 1; - if indices[idx] < dimensions[idx].1.len() { + if matches!(dims[idx].1, Dim::Fuzz { .. }) { + continue; + } + det_indices[idx] += 1; + if det_indices[idx] < det_lens[idx] { break; } - indices[idx] = 0; + det_indices[idx] = 0; } } } @@ -338,6 +459,7 @@ fn materialize_param_values( test_attribute_loc: &Loc, var_loc: &Loc, ty: &Type, + param_name: &str, spec: &ParamSpec, ) -> Option> { match spec { @@ -359,7 +481,14 @@ fn materialize_param_values( Some(out) }, ParamSpec::Fuzz { domain, exclude } => { - match fuzz_source.sample(ty, domain, exclude, DEFAULT_FUZZ_ITERATIONS, DEFAULT_FUZZ_SEED) + match fuzz_source.sample( + ty, + param_name, + domain, + exclude, + DEFAULT_FUZZ_ITERATIONS, + DEFAULT_FUZZ_SEED, + ) { Ok(vs) if vs.is_empty() => { env.error_with_labels(fn_id_loc, "unable to generate test", vec![ @@ -508,16 +637,19 @@ fn merge_test_param_entry( }, Attribute::Constrained(id, sym, op, val) => { let entry_loc = env.get_node_loc(*id); - // Build/extend a Fuzz spec for this parameter. + // Build/extend a Fuzz spec for this parameter. If `_a = ...` was already + // seen, restore the existing spec after reporting the mix error so the + // function's other parameters can still be analyzed coherently. let existing = specs.remove(sym); let (mut domain, mut exclude) = match existing { None => (Domain::default(), Domain::default()), Some(ParamSpec::Fuzz { domain, exclude }) => (domain, exclude), - Some(_) => { + Some(other) => { env.error( &entry_loc, "Cannot mix `=` with `!=` / `in` for the same parameter", ); + specs.insert(*sym, other); return false; }, }; diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index 5d462e71317..e48ec6dfed4 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -6,8 +6,10 @@ use anyhow::bail; use codespan_reporting::{diagnostic::Severity, term::termcolor::Buffer}; use libtest_mimic::{Arguments, Trial}; use move_compiler_v2::{ - annotate_units, disassemble_compiled_units, logging, pipeline, plan_builder, - run_bytecode_verifier, run_file_format_gen, Experiment, Options, + annotate_units, disassemble_compiled_units, + fuzz::{DefaultFuzzSource, FuzzConfig}, + logging, pipeline, plan_builder, run_bytecode_verifier, run_file_format_gen, Experiment, + Options, }; use move_model::{metadata::LanguageVersion, model::GlobalEnv, sourcifier::Sourcifier}; use move_prover_test_utils::{baseline_test, extract_test_directives}; @@ -641,7 +643,8 @@ fn run_flow_similar_to_compiler(config: &TestConfig, options: &Options) -> anyho // Build the test plan here to parse and validate any test-related attributes in the AST. // In real use, this is run outside of the compilation process, but the needed info is // available in `env` once we finish the AST. - plan_builder::construct_test_plan(&env, None); + let fuzz_source = DefaultFuzzSource::new(&env, FuzzConfig::default()); + plan_builder::construct_test_plan_with_fuzz_source(&env, None, &fuzz_source); ok = check_diags(&mut test_output.borrow_mut(), &env, options); } diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp index d43293de1f9..64e981b27f6 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp @@ -1,57 +1,46 @@ Diagnostics: -error: unable to generate test +note: fuzz: expanded `ne_single` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:6:16 │ -5 │ #[test(_a != @0x42)] - │ ----------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 6 │ public fun ne_single(_a: signer) { } - │ ^^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^^ -error: unable to generate test +note: fuzz: expanded `ne_list` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:9:16 │ -8 │ #[test(_a != [@0x42, @0x41])] - │ -------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 9 │ public fun ne_list(_a: signer) { } - │ ^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^ -error: unable to generate test +note: fuzz: expanded `in_list` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:12:16 │ -11 │ #[test(_a in [@0x1, @0x2, @0x3])] - │ ------------------------------ no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 12 │ public fun in_list(_a: signer) { } - │ ^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^ -error: unable to generate test +note: fuzz: expanded `in_inclusive_range` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:15:16 │ -14 │ #[test(_a in 1..=10)] - │ ------------------ no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 15 │ public fun in_inclusive_range(_a: signer) { } - │ ^^^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^^^^^^^^^^^ -error: unable to generate test +note: fuzz: expanded `in_half_open_range` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:18:16 │ -17 │ #[test(_a in 1..10)] - │ ----------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 18 │ public fun in_half_open_range(_a: signer) { } - │ ^^^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^^^^^^^^^^^ -error: unable to generate test +note: fuzz: expanded `in_union` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:21:16 │ -20 │ #[test(_a in @0x1 | @0x5..=@0x10 | @0x20)] - │ --------------------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 21 │ public fun in_union(_a: signer) { } - │ ^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^ -error: unable to generate test +note: fuzz: expanded `in_with_excludes` to 16 cases ┌─ tests/unit_test/test/fuzz_constraints.move:26:16 │ -25 │ #[test(_a in [@0x1, @0x2, @0x3], _a != @0x2)] - │ ------------------------------------------ no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 26 │ public fun in_with_excludes(_a: signer) { } - │ ^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^^^^^^^^^ + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp new file mode 100644 index 00000000000..d4ef6630c54 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp @@ -0,0 +1,10 @@ + +Diagnostics: +note: fuzz: expanded `fuzz_with_fixtures` to 16 cases + ┌─ tests/unit_test/test/fuzz_fixtures.move:11:16 + │ +11 │ public fun fuzz_with_fixtures(_amount: u64, _recipient: address, _salt: u32) { } + │ ^^^^^^^^^^^^^^^^^^ + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.move new file mode 100644 index 00000000000..92dc0017bb0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.move @@ -0,0 +1,12 @@ +// User-declared fixtures. The default fuzz source mines `FIXTURE_` +// constants from the module and pipes them into the matching parameter's +// candidate pool ahead of random + edge values. +module 0x1::M { + const FIXTURE_AMOUNT: u64 = 42; + const FIXTURE_AMOUNT_HI: u64 = 18446744073709551610; + const FIXTURE_RECIPIENT: address = @0xCAFE; + + // `amount` and `recipient` get fixture-biased draws; `salt` does not. + #[test] + public fun fuzz_with_fixtures(_amount: u64, _recipient: address, _salt: u32) { } +} diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp index 92cc851f4bf..8d0ff1e1467 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp @@ -1,25 +1,16 @@ Diagnostics: -error: unable to generate test +note: fuzz: expanded `bare_with_signer` to 16 cases ┌─ tests/unit_test/test/fuzz_implicit.move:6:16 │ -5 │ #[test] - │ ---- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 6 │ public fun bare_with_signer(_a: signer) { } - │ ^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^^^^^^^^^ -error: unable to generate test +note: fuzz: expanded `bare_with_two` to 16 cases ┌─ tests/unit_test/test/fuzz_implicit.move:9:16 │ -8 │ #[test] - │ ---- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion 9 │ public fun bare_with_two(_a: signer, _b: address) { } - │ ^^^^^^^^^^^^^ -- Corresponding to this parameter + │ ^^^^^^^^^^^^^ -error: unable to generate test - ┌─ tests/unit_test/test/fuzz_implicit.move:9:16 - │ -8 │ #[test] - │ ---- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion -9 │ public fun bare_with_two(_a: signer, _b: address) { } - │ ^^^^^^^^^^^^^ -- Corresponding to this parameter + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp index 7045cbafc23..1ae6704f615 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_mix_assign_constraint.exp @@ -6,24 +6,8 @@ error: Cannot mix `=` with `!=` / `in` for the same parameter 3 │ #[test(_a = @0x1, _a != @0x2)] │ ^^^^^^^^^^ -error: unable to generate test - ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:4:16 - │ -3 │ #[test(_a = @0x1, _a != @0x2)] - │ --------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion -4 │ public fun mix_eq_then_ne(_a: signer) { } - │ ^^^^^^^^^^^^^^ -- Corresponding to this parameter - error: Cannot mix `=` with `!=` / `in` for the same parameter ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:6:12 │ 6 │ #[test(_a != @0x2, _a = @0x1)] │ ^^^^^^^^^^ - -error: unable to generate test - ┌─ tests/unit_test/test/fuzz_mix_assign_constraint.move:7:16 - │ -6 │ #[test(_a != @0x2, _a = @0x1)] - │ --------------------------- no fuzz value source is registered; install a `FuzzValueSource` to enable implicit-fuzz #[test] expansion -7 │ public fun mix_ne_then_eq(_a: signer) { } - │ ^^^^^^^^^^^^^^ -- Corresponding to this parameter diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp new file mode 100644 index 00000000000..ee33b483b12 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp @@ -0,0 +1,52 @@ + +Diagnostics: +note: fuzz: expanded `fuzz_u64` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:7:16 + │ +7 │ public fun fuzz_u64(_a: u64) { } + │ ^^^^^^^^ + +note: fuzz: expanded `fuzz_u8` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:10:16 + │ +10 │ public fun fuzz_u8(_a: u8) { } + │ ^^^^^^^ + +note: fuzz: expanded `fuzz_bool` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:13:16 + │ +13 │ public fun fuzz_bool(_a: bool) { } + │ ^^^^^^^^^ + +note: fuzz: expanded `fuzz_address` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:16:16 + │ +16 │ public fun fuzz_address(_a: address) { } + │ ^^^^^^^^^^^^ + +note: fuzz: expanded `fuzz_pair` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:19:16 + │ +19 │ public fun fuzz_pair(_a: u64, _b: address) { } + │ ^^^^^^^^^ + +note: fuzz: expanded `fuzz_range_u64` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:22:16 + │ +22 │ public fun fuzz_range_u64(_a: u64) { } + │ ^^^^^^^^^^^^^^ + +note: fuzz: expanded `fuzz_exclude_u64` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:25:16 + │ +25 │ public fun fuzz_exclude_u64(_a: u64) { } + │ ^^^^^^^^^^^^^^^^ + +note: fuzz: expanded `fuzz_addr_list` to 16 cases + ┌─ tests/unit_test/test/fuzz_primitives.move:28:16 + │ +28 │ public fun fuzz_addr_list(_a: signer) { } + │ ^^^^^^^^^^^^^^ + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.move new file mode 100644 index 00000000000..a0018150ee7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.move @@ -0,0 +1,29 @@ +// End-to-end: implicit fuzz on primitive types now produces actual test cases. +// Diagnostics-side, all we see is the `[NOTE] fuzz: expanded …` line per +// function — the expanded cases live in the runner's plan, not in compiler +// diagnostics. +module 0x1::M { + #[test] + public fun fuzz_u64(_a: u64) { } + + #[test] + public fun fuzz_u8(_a: u8) { } + + #[test] + public fun fuzz_bool(_a: bool) { } + + #[test] + public fun fuzz_address(_a: address) { } + + #[test] + public fun fuzz_pair(_a: u64, _b: address) { } + + #[test(_a in 1..=10)] + public fun fuzz_range_u64(_a: u64) { } + + #[test(_a != 42)] + public fun fuzz_exclude_u64(_a: u64) { } + + #[test(_a in [@0x1, @0x2, @0x3])] + public fun fuzz_addr_list(_a: signer) { } +} diff --git a/third_party/move/tools/move-unit-test/src/lib.rs b/third_party/move/tools/move-unit-test/src/lib.rs index 8d4964d6a00..45854d5ad9d 100644 --- a/third_party/move/tools/move-unit-test/src/lib.rs +++ b/third_party/move/tools/move-unit-test/src/lib.rs @@ -14,7 +14,24 @@ use legacy_move_compiler::{ unit_test::TestPlan, }; use move_command_line_common::files::verify_and_create_named_address_mapping; -use move_compiler_v2::plan_builder as plan_builder_v2; +use legacy_move_compiler::unit_test::TestCase; +use move_compiler_v2::{ + fuzz::{DefaultFuzzSource, FuzzConfig, FuzzPlanMetadata, FuzzValueSource}, + fuzz_corpus, plan_builder as plan_builder_v2, +}; +use std::sync::Arc; + +/// Sidecar attached to [`TestPlan::runner_metadata`] when a fuzz source is +/// active. The runner downcasts to this type to drive shrinking on failing +/// fuzz cases and corpus persistence. Holding both the metadata and the +/// source means the runner doesn't need to know how to build either. +pub struct FuzzRunnerCtx { + pub metadata: FuzzPlanMetadata, + pub source: Arc, + /// When set, the runner appends failing fuzz arguments to + /// `/failures/...` and replays prior entries on next run. + pub corpus_dir: Option, +} use move_core_types::{effects::ChangeSet, language_storage::ModuleId}; use move_model::metadata::{CompilerVersion, LanguageVersion}; use move_package::compilation::compiled_package::build_and_report_v2_driver; @@ -102,6 +119,27 @@ pub struct UnitTestingConfig { /// Verbose mode #[clap(short = 'v', long = "verbose")] pub verbose: bool, + + /// Number of values to sample per implicit-fuzz `#[test]` parameter. + #[clap(long = "fuzz-runs", default_value_t = 16)] + pub fuzz_runs: usize, + + /// Deterministic seed for the fuzz value source. Defaults to 0; change to + /// search the space differently across CI runs. + #[clap(long = "fuzz-seed", default_value_t = 0)] + pub fuzz_seed: u64, + + /// Percentage weight (0..=100) of dictionary draws against random+edge + /// draws when fuzzing primitive parameters. Mirrors Foundry's + /// `dictionary_weight`. + #[clap(long = "fuzz-dictionary-weight", default_value_t = 40)] + pub fuzz_dictionary_weight: u8, + + /// Directory used as the fuzz corpus. When set, regression cases from + /// `/failures/` are replayed alongside fresh fuzz draws, and any + /// fuzz-generated test that fails is appended to it. Disabled by default. + #[clap(long = "fuzz-corpus-dir")] + pub fuzz_corpus_dir: Option, } fn format_module_id(module_id: &ModuleId) -> String { @@ -127,6 +165,10 @@ impl Default for UnitTestingConfig { verbose: false, list: false, named_address_values: vec![], + fuzz_runs: 16, + fuzz_seed: 0, + fuzz_dictionary_weight: 40, + fuzz_corpus_dir: None, } } } @@ -148,7 +190,7 @@ impl UnitTestingConfig { ) -> Option { let addresses = verify_and_create_named_address_mapping(self.named_address_values.clone()).ok()?; - let (test_plan, files, units) = { + let (build_opt, files, units, fuzz_source) = { let options = move_compiler_v2::Options { compile_test_code: true, testing: true, @@ -163,10 +205,72 @@ impl UnitTestingConfig { ..Default::default() }; let (files, units, env) = build_and_report_v2_driver(options).unwrap(); - let test_plan = plan_builder_v2::construct_test_plan(&env, None); - (test_plan, files, units) + let fuzz_config = FuzzConfig { + runs: self.fuzz_runs, + seed: self.fuzz_seed, + dictionary_weight: self.fuzz_dictionary_weight, + ..FuzzConfig::default() + }; + let fuzz_source: Arc = + Arc::new(DefaultFuzzSource::new(&env, fuzz_config)); + let build_opt = plan_builder_v2::construct_test_plan_with_fuzz_source( + &env, + None, + fuzz_source.as_ref(), + ); + (build_opt, files, units, fuzz_source) }; - test_plan.map(|tests| TestPlan::new(tests, files, units, vec![])) + build_opt.map(|build| { + let mut plans = build.plans; + // Topic 2: replay regression corpus by appending saved failing + // argument vectors as extra TestCases. The runner re-runs them + // before the fresh fuzz draws. + if let Some(corpus_dir) = self.fuzz_corpus_dir.as_ref() { + for module_plan in plans.iter_mut() { + let module_id = module_plan.module_id.clone(); + // Snapshot the existing case names so we don't replay against + // already-replayed regressions. + let test_names: Vec = + module_plan.tests.keys().cloned().collect(); + for original_name in test_names { + let function_stem = original_name + .split_once('[') + .map(|(stem, _)| stem.to_string()) + .unwrap_or(original_name.clone()); + let regressions = fuzz_corpus::load_failures( + corpus_dir, + &module_id, + &function_stem, + ) + .unwrap_or_default(); + for (i, args) in regressions.into_iter().enumerate() { + // Inherit expected_failure shape from the original + // case so abort-code expectations replay too. + let template = module_plan.tests.get(&original_name).cloned(); + let expected_failure = template + .as_ref() + .and_then(|c| c.expected_failure.clone()); + let replay_name = format!("{}#regression[{}]", function_stem, i); + module_plan.tests.insert( + replay_name.clone(), + TestCase { + test_name: replay_name, + arguments: args, + expected_failure, + }, + ); + } + } + } + } + let mut plan = TestPlan::new(plans, files, units, vec![]); + plan.runner_metadata = Some(Arc::new(FuzzRunnerCtx { + metadata: build.fuzz_metadata, + source: fuzz_source, + corpus_dir: self.fuzz_corpus_dir.clone(), + })); + plan + }) } /// Build a test plan from a unit test config diff --git a/third_party/move/tools/move-unit-test/src/test_runner.rs b/third_party/move/tools/move-unit-test/src/test_runner.rs index 61ed138d48f..41f49a592f0 100644 --- a/third_party/move/tools/move-unit-test/src/test_runner.rs +++ b/third_party/move/tools/move-unit-test/src/test_runner.rs @@ -9,11 +9,13 @@ use crate::{ UnitTestFactory, }, }; +use crate::FuzzRunnerCtx; use anyhow::Result; use colored::*; use legacy_move_compiler::unit_test::{ ExpectedFailure, ModuleTestPlan, NamedOrBytecodeModule, TestCase, TestPlan, }; +use move_compiler_v2::fuzz::ArgOrigin; use move_binary_format::{ errors::{Location, VMResult}, file_format::CompiledModule, @@ -47,6 +49,9 @@ pub struct SharedTestingConfig { #[allow(dead_code)] // used by some features source_files: Vec, record_writeset: bool, + /// Set when a fuzz source was attached to the [`TestPlan`]. The runner + /// uses this to shrink failing fuzz cases into a minimal counterexample. + fuzz_ctx: Option>, } pub struct TestRunner { @@ -139,6 +144,11 @@ impl TestRunner { starting_storage_state.apply(genesis_state)?; } + let fuzz_ctx = tests + .runner_metadata + .as_ref() + .and_then(|m| m.clone().downcast::().ok()); + Ok(Self { testing_config: SharedTestingConfig { save_storage_state_on_failure, @@ -146,6 +156,7 @@ impl TestRunner { starting_storage_state, source_files, record_writeset, + fuzz_ctx, }, num_threads, tests, @@ -234,9 +245,141 @@ impl TestOutput<'_, '_, W> { ) .unwrap(); } + + /// Free-form note printed underneath the last status line. Used by the + /// shrink path to surface the minimal counterexample. + fn note(&self, message: &str) { + writeln!(self.writer.lock().unwrap(), " {}", message).unwrap() + } +} + +/// Human-readable argument vector used in shrink output. +fn format_arguments(args: &[move_core_types::value::MoveValue]) -> String { + use move_core_types::value::MoveValue; + let parts: Vec = args + .iter() + .map(|v| match v { + MoveValue::Address(a) | MoveValue::Signer(a) => { + format!("@{}", a.short_str_lossless()) + }, + MoveValue::U8(x) => x.to_string(), + MoveValue::U16(x) => x.to_string(), + MoveValue::U32(x) => x.to_string(), + MoveValue::U64(x) => x.to_string(), + MoveValue::U128(x) => x.to_string(), + MoveValue::U256(x) => x.to_string(), + MoveValue::Bool(b) => b.to_string(), + other => format!("{:?}", other), + }) + .collect(); + format!("[{}]", parts.join(", ")) } impl SharedTestingConfig { + /// Topic 2: write the failing argument vector to the regression corpus + /// when a corpus directory is configured. Prefers the shrunk-minimal + /// vector when available — that's the cleanest reproducer to persist. + fn persist_to_corpus( + &self, + test_plan: &ModuleTestPlan, + function_name: &str, + test_info: &TestCase, + shrunk: Option<&[move_core_types::value::MoveValue]>, + ) { + let Some(ctx) = self.fuzz_ctx.as_ref() else { return }; + let Some(dir) = ctx.corpus_dir.as_ref() else { return }; + // Only persist if this case was fuzz-origin. Regressions don't need + // saving again — they're already on disk. + let origins = ctx.metadata.get(&test_plan.module_id, function_name); + if origins.is_none() || origins.unwrap().iter().all(|o| matches!(o, ArgOrigin::Fixed)) { + return; + } + // The function stem is the test name without the expansion suffix. + let stem = function_name + .split_once('[') + .map(|(s, _)| s.to_string()) + .unwrap_or_else(|| function_name.to_string()); + let args = shrunk.unwrap_or(test_info.arguments.as_slice()); + // Best-effort: ignore filesystem errors so a stuck corpus path doesn't + // mask the underlying test failure. + let _ = move_compiler_v2::fuzz_corpus::append_failure( + dir, + &test_plan.module_id, + &stem, + args, + ); + } + + /// If the failing case was a fuzz-generated case, walk the shrinker until + /// no further shrink reproduces the failure. Returns the minimal failing + /// argument vector, or `None` when shrinking is not applicable (no fuzz + /// context, no fuzz arguments, or already minimal). + /// + /// Bound: 100 total shrink steps per case. Each step tries one shrink per + /// fuzzed argument and accepts the first one that still fails. + fn shrink_if_fuzz( + &self, + test_plan: &ModuleTestPlan, + function_name: &str, + test_info: &TestCase, + factory: &Mutex, + ) -> Option> { + let ctx = self.fuzz_ctx.as_ref()?; + let origins = ctx.metadata.get(&test_plan.module_id, function_name)?; + if origins.iter().all(|o| matches!(o, ArgOrigin::Fixed)) { + return None; + } + let mut current = test_info.arguments.clone(); + let mut improved_at_least_once = false; + for _ in 0..100 { + let mut improved = false; + for (i, origin) in origins.iter().enumerate() { + let (param_name, ty, domain, exclude) = match origin { + ArgOrigin::Fuzz { + param_name, + ty, + domain, + exclude, + } => (param_name, ty, domain, exclude), + ArgOrigin::Fixed => continue, + }; + let candidate_value = ctx.source.shrink( + ty, + param_name, + ¤t[i], + domain, + exclude, + ); + let Some(smaller) = candidate_value else { + continue; + }; + let mut candidate = current.clone(); + candidate[i] = smaller; + let probe = TestCase { + test_name: test_info.test_name.clone(), + arguments: candidate.clone(), + expected_failure: test_info.expected_failure.clone(), + }; + let (_, _, exec_result, _) = + self.execute_via_move_vm(test_plan, function_name, &probe, factory); + if exec_result.is_err() { + current = candidate; + improved = true; + improved_at_least_once = true; + break; + } + } + if !improved { + break; + } + } + if improved_at_least_once { + Some(current) + } else { + None + } + } + #[allow(clippy::field_reassign_with_default)] fn execute_via_move_vm( &self, @@ -427,6 +570,29 @@ impl SharedTestingConfig { }, None => { output.fail(function_name); + // Topic 3: if this test failure originated from a fuzz-sampled + // case, attempt to shrink it to a minimal counterexample and + // print the result alongside the failure. + let shrunk = self.shrink_if_fuzz( + test_plan, + function_name, + test_info, + factory, + ); + if let Some(args) = shrunk.as_ref() { + output.note(&format!( + "└─ minimal counterexample: {}", + format_arguments(args) + )); + } + // Topic 2: persist failing fuzz arguments to the + // regression corpus so the next run replays them. + self.persist_to_corpus( + test_plan, + function_name, + test_info, + shrunk.as_deref(), + ); stats.test_failure( TestFailure::new( FailureReason::unexpected_error(actual_err), From 4f04007729decf47d1ae5a323bb10ecd1d8b43da Mon Sep 17 00:00:00 2001 From: primata Date: Mon, 18 May 2026 18:19:02 -0300 Subject: [PATCH 3/9] handle empty array of values --- .../move/move-compiler-v2/src/plan_builder.rs | 16 ++++++++++++++++ .../tests/unit_test/test/fuzz_empty_matrix.exp | 9 +++++++++ .../tests/unit_test/test/fuzz_empty_matrix.move | 7 +++++++ 3 files changed, 32 insertions(+) create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.move diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index 2d8a931980c..3ba04e755c4 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -466,6 +466,22 @@ fn materialize_param_values( ParamSpec::Concrete(v) => coerce_to_param_type(env, fn_id_loc, test_attribute_loc, var_loc, ty, v.clone()) .map(|v| vec![v]), ParamSpec::Matrix(vs) => { + if vs.is_empty() { + // `_a = []` would produce zero test cases for this dim, which + // collapses Cartesian expansion to zero total cases and trips + // the dimension-indexing loop in `build_test_info`. + env.error_with_labels(fn_id_loc, "unable to generate test", vec![ + ( + test_attribute_loc.clone(), + "Empty matrix `[]` produces no test cases".to_string(), + ), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); + return None; + } let mut out = Vec::with_capacity(vs.len()); for v in vs { let coerced = coerce_to_param_type( diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.exp new file mode 100644 index 00000000000..504bc80fdca --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_empty_matrix.move:6:16 + │ +5 │ #[test(_a = [])] + │ ------------- Empty matrix `[]` produces no test cases +6 │ public fun empty_matrix(_a: u64) { } + │ ^^^^^^^^^^^^ -- Corresponding to this parameter diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.move new file mode 100644 index 00000000000..b072e1bfd17 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_empty_matrix.move @@ -0,0 +1,7 @@ +// `_a = []` is a programmer error: it would produce zero cases for this +// dimension. We report a diagnostic at plan-build time instead of crashing +// the runner with an out-of-bounds index. +module 0x1::M { + #[test(_a = [])] + public fun empty_matrix(_a: u64) { } +} From aafd73e115acc296d17e5f5adc7ab8ed6a3f01aa Mon Sep 17 00:00:00 2001 From: primata Date: Tue, 2 Jun 2026 00:39:12 -0300 Subject: [PATCH 4/9] code review --- .../legacy-move-compiler/src/unit_test/mod.rs | 7 + third_party/move/move-compiler-v2/src/fuzz.rs | 78 ++++++-- .../move/move-compiler-v2/src/fuzz_corpus.rs | 6 +- .../move/move-compiler-v2/src/plan_builder.rs | 178 ++++++++++++++++-- .../move/tools/move-unit-test/src/lib.rs | 56 +++--- .../tools/move-unit-test/src/test_runner.rs | 18 +- .../tools/move-unit-test/tests/fuzz_runner.rs | 101 ++++++++++ 7 files changed, 376 insertions(+), 68 deletions(-) create mode 100644 third_party/move/tools/move-unit-test/tests/fuzz_runner.rs diff --git a/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs b/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs index 1455676914d..bcb99dfa6c5 100644 --- a/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs +++ b/third_party/move/move-compiler-v2/legacy-move-compiler/src/unit_test/mod.rs @@ -47,7 +47,14 @@ pub struct ModuleTestPlan { #[derive(Debug, Clone)] pub struct TestCase { + /// Display/identity name of this case. For fuzz/matrix expansion this is + /// decorated and made unique (e.g. `foo#3[a=42]`), so it is NOT a valid + /// Move identifier and must not be used to look up the function. pub test_name: TestName, + /// The real Move function symbol to invoke (e.g. `foo`). Always a valid + /// identifier. Runners must use this — not `test_name` — when loading the + /// function from the VM. + pub function_name: TestName, pub arguments: Vec, pub expected_failure: Option, } diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs index 54f5dac49c2..0e03b0c57ae 100644 --- a/third_party/move/move-compiler-v2/src/fuzz.rs +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -137,6 +137,11 @@ pub trait FuzzValueSource: Send + Sync { /// from `domain` (unrestricted when empty) and avoiding any value in /// `exclude`. `seed` is provided for reproducibility. /// + /// Passing `n == 0` requests the source's own configured run count (for + /// [`DefaultFuzzSource`] that is [`FuzzConfig::runs`]). Callers that are + /// generic over the source — like the plan builder — pass `0` so the + /// `--fuzz-runs` setting is honored instead of a hardcoded count. + /// /// `param_name` enables Foundry-style fixtures — sources can route /// per-parameter using user-declared `FIXTURE_` constants. The /// caller passes the parameter's display string so the trait doesn't @@ -212,8 +217,15 @@ impl FuzzValueSource for NoFuzzSource { // Configuration // --------------------------------------------------------------------------- -/// Tunables for [`DefaultFuzzSource`]. Defaults mirror Foundry's `[fuzz]` -/// section so users coming from EVM tooling find familiar knobs. +/// Tunables for [`DefaultFuzzSource`]. The knob *names* mirror Foundry's +/// `[fuzz]` section so users coming from EVM tooling find familiar dials, but +/// the defaults are not identical: `runs` defaults to 16 rather than Foundry's +/// 256. The lower default is intentional — each case is a full in-process +/// MoveVM execution, and the plan builder Cartesian-multiplies fuzz `runs` +/// against any explicit `#[test]` matrices under a `MAX_FUZZ_CASES` (1024) cap, +/// so a 256 default would blow that ceiling as soon as a test has a couple of +/// matrix dimensions. Raise `runs` (or `--fuzz-runs`) for deeper search. +/// `dictionary_weight` does match Foundry's default of 40. #[derive(Clone, Debug)] pub struct FuzzConfig { /// Number of samples drawn per implicit-fuzz parameter. @@ -491,12 +503,6 @@ impl Rng { z ^ (z >> 31) } - fn next_u128(&mut self) -> u128 { - let hi = self.next_u64() as u128; - let lo = self.next_u64() as u128; - (hi << 64) | lo - } - fn pick<'a, T>(&mut self, xs: &'a [T]) -> Option<&'a T> { if xs.is_empty() { None @@ -663,8 +669,21 @@ fn sample_addresses( } } + // Finite literal domain with no ranges: random/edge draws almost never + // land in the listed set, so draw straight from it (with repeats) to fill + // `n` rather than returning fewer values and capping the run count. + let literal_only = !dom_addrs.is_empty() && dom_ranges.is_empty(); + while out.len() < n && tries < cap { tries += 1; + if literal_only { + match rng.pick(&dom_addrs).copied() { + Some(a) if !is_excluded(&a) => out.push(wrap(a)), + Some(_) => {}, + None => break, + } + continue; + } let pick = rng.next_u64() % 100; let candidate = if pick < u64::from(EDGE_WEIGHT) { // Edge: well-known anchors. @@ -781,15 +800,28 @@ fn sample_uints( let mut tries = 0usize; let cap = n.saturating_mul(max_retry_multiplier).max(1); + // When the domain is a finite set of literals (no ranges), random/edge/dict + // draws almost never land in the set, so we'd return far fewer than `n` + // values — which then caps the whole function's run count via the zip in + // the plan builder. Draw straight from the literal set instead. + let literal_only = domain_active && dom_ranges.is_empty(); while out.len() < n && tries < cap { tries += 1; let pick = rng.next_u64() % 100; - let candidate = if pick < edge_cutoff { + let candidate = if literal_only { + // Cycle through the listed values (with repeats) to fill `n`. + match rng.pick(&dom_lits) { + Some(v) => v.clone(), + None => break, + } + } else if pick < edge_cutoff { // Edge sample. If a domain range is active, draw an edge value - // bracketed against the active range. + // bracketed against the active range — honoring the half-open + // upper bound so we never emit the excluded `hi`. if let Some((lo, hi, inc)) = rng.pick(&dom_ranges).cloned() { - let endpoints = [lo.clone(), hi.clone(), &lo + 1, if inc { hi } else { &hi - 1 }]; + let hi_edge = if inc { hi } else { &hi - 1 }; + let endpoints = [lo.clone(), &lo + 1, &hi_edge - 1, hi_edge]; rng.pick(&endpoints).cloned().unwrap_or_else(BigInt::default) } else { rng.pick(&edges).cloned().unwrap_or_else(BigInt::default) @@ -801,7 +833,10 @@ fn sample_uints( let (lo, hi, inc) = rng.pick(&dom_ranges).cloned().unwrap(); sample_bigint_in_range(rng, &lo, &hi, inc) } else { - BigInt::from(rng.next_u128() % modulus.clone().to_u128().unwrap_or(u128::MAX).max(1)) + // Full-width random draw. Going through `u128` here would cap u128 + // at 2^128-1 (unreachable max) and clamp u256 to its low 128 bits, + // so draw enough limbs to cover the whole type instead. + random_bigint_below(rng, &modulus) }; // Coerce candidate into the type's representable range. let candidate = ((&candidate % &modulus) + &modulus) % &modulus; @@ -944,6 +979,25 @@ fn limbs_to_u32(u64s: &[u64]) -> Vec { out } +/// Draw a (uniform-ish) random `BigInt` in `[0, modulus)` for any Move uint +/// width. Generates one extra limb beyond the modulus width before reducing, +/// so the high end of wide types (u128 max, the upper 128 bits of u256) is +/// reachable; a small modulo bias is acceptable for fuzzing. +fn random_bigint_below(rng: &mut Rng, modulus: &BigInt) -> BigInt { + if modulus <= &BigInt::from(1) { + return BigInt::from(0); + } + // Bits in `modulus`; one extra 64-bit limb makes the reduction bias + // negligible across the whole range. + let limbs = ((modulus.bits() / 64) + 1).max(1) as usize; + let mut words = Vec::with_capacity(limbs); + for _ in 0..limbs { + words.push(rng.next_u64()); + } + let raw = BigInt::from_slice(Sign::Plus, &limbs_to_u32(&words)); + raw % modulus +} + // --------------------------------------------------------------------------- // Shrinking — Topic 3 // --------------------------------------------------------------------------- diff --git a/third_party/move/move-compiler-v2/src/fuzz_corpus.rs b/third_party/move/move-compiler-v2/src/fuzz_corpus.rs index b200920dfa4..47720499105 100644 --- a/third_party/move/move-compiler-v2/src/fuzz_corpus.rs +++ b/third_party/move/move-compiler-v2/src/fuzz_corpus.rs @@ -194,7 +194,9 @@ pub fn append_failure( let key = to_wire(args).and_then(|w| bcs::to_bytes(&w).map_err(Into::into)); let key = match key { Ok(k) => k, - Err(_) => return Ok(()), // unsupported variant; silently skip + // Propagate rather than silently dropping: a failure we can't persist + // must not look like a successfully-saved regression. + Err(e) => return Err(e.context("corpus: cannot serialize failing arguments")), }; if seen.insert(key) { existing.push(args.to_vec()); @@ -225,7 +227,7 @@ pub fn append_seed( let key = to_wire(args).and_then(|w| bcs::to_bytes(&w).map_err(Into::into)); let key = match key { Ok(k) => k, - Err(_) => return Ok(()), + Err(e) => return Err(e.context("corpus: cannot serialize seed arguments")), }; if seen.insert(key) { existing.push(args.to_vec()); diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index 3ba04e755c4..17d3a9cc5fd 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -24,7 +24,8 @@ use legacy_move_compiler::{ }; use move_command_line_common::{address::NumericalAddress, parser::NumberFormat}; use move_core_types::{ - identifier::Identifier, language_storage::ModuleId, value::MoveValue, vm_status::StatusCode, + identifier::Identifier, language_storage::ModuleId, u256, value::MoveValue, + vm_status::StatusCode, }; use move_model::{ ast::{Address, Attribute, AttributeValue, ConstraintOp, ModuleName, Value}, @@ -32,13 +33,14 @@ use move_model::{ symbol::Symbol, ty::{PrimitiveType, Type}, }; -use num::{BigInt, ToPrimitive}; +use num::{bigint::Sign, BigInt, ToPrimitive}; use std::collections::BTreeMap; -/// Default number of values to draw per fuzzed parameter. -const DEFAULT_FUZZ_ITERATIONS: usize = 16; -/// Default deterministic seed if the caller does not override. -const DEFAULT_FUZZ_SEED: u64 = 0; +/// Sentinel run count handed to `FuzzValueSource::sample`: `0` means "use the +/// source's own configured `runs`" (e.g. `FuzzConfig::runs`, driven by +/// `--fuzz-runs`). The planner is generic over the source and has no config of +/// its own, so it defers the count to the source rather than hardcoding it. +const FUZZ_RUNS_FROM_SOURCE: usize = 0; /// Cap on Cartesian-product expansion to guard against accidental explosion. const MAX_FUZZ_CASES: usize = 1024; @@ -243,7 +245,7 @@ fn build_test_info( }, } let mut dims: Vec<(Symbol, Dim)> = Vec::with_capacity(parameters.len()); - for param in ¶meters { + for (param_index, param) in parameters.iter().enumerate() { let Parameter(var, ty, var_loc) = param; let owned_default; let spec_ref = match specs.get(var) { @@ -266,6 +268,11 @@ fn build_test_info( var_loc, ty, param_name.as_str(), + // Per-parameter salt: derived from the parameter position so two + // fuzz parameters of the same type draw distinct value streams + // rather than identical ones. The source mixes this with its own + // base seed (`--fuzz-seed`). + param_index as u64, spec_ref, ) { Some(values) => { @@ -347,6 +354,7 @@ fn build_test_info( return vec![ExpandedCase { case: TestCase { test_name: fn_name_str.to_string(), + function_name: fn_name_str.to_string(), arguments: Vec::new(), expected_failure, }, @@ -400,14 +408,25 @@ fn build_test_info( }, }); } + // The display name embeds the case ordinal so it is unique even when + // two expansions draw the same argument values (e.g. a `bool` fuzz + // param, or a narrow domain). Without the ordinal these collide in + // the per-module `BTreeMap` and cases are silently + // dropped. The ordinal is the case's position in `cases`. let test_name = if is_single { fn_name_str.to_string() } else { - format!("{}[{}]", fn_name_str, suffix_parts.join(",")) + format!( + "{}#{}[{}]", + fn_name_str, + cases.len(), + suffix_parts.join(",") + ) }; cases.push(ExpandedCase { case: TestCase { test_name, + function_name: fn_name_str.to_string(), arguments, expected_failure: expected_failure.clone(), }, @@ -460,6 +479,7 @@ fn materialize_param_values( var_loc: &Loc, ty: &Type, param_name: &str, + seed: u64, spec: &ParamSpec, ) -> Option> { match spec { @@ -502,8 +522,9 @@ fn materialize_param_values( param_name, domain, exclude, - DEFAULT_FUZZ_ITERATIONS, - DEFAULT_FUZZ_SEED, + // `0` => let the source use its configured `runs` (`--fuzz-runs`). + FUZZ_RUNS_FROM_SOURCE, + seed, ) { Ok(vs) if vs.is_empty() => { @@ -555,21 +576,116 @@ fn coerce_to_param_type( Some(MoveValue::Signer(*addr)) }, (MoveValue::Address(_), Type::Primitive(PrimitiveType::Address)) => Some(value), + (MoveValue::Bool(_), Type::Primitive(PrimitiveType::Bool)) => Some(value), + // Integer carrier -> the parameter's actual width, with a range check. + (_, Type::Primitive(prim)) if is_uint_prim(prim) => match move_value_as_bigint(&value) { + Some(n) => { + coerce_numeric_to_width(env, fn_id_loc, test_attribute_loc, var_loc, prim, &n) + }, + None => { + coerce_type_error(env, fn_id_loc, test_attribute_loc, var_loc); + None + }, + }, _ => { - let err_msg = "Unexpected argument type: expect an address or a signer"; - let invalid_test = "unable to generate test"; - env.error_with_labels(fn_id_loc, invalid_test, vec![ - (test_attribute_loc.clone(), err_msg.to_string()), - ( - var_loc.clone(), - "Corresponding to this parameter".to_string(), - ), - ]); + coerce_type_error(env, fn_id_loc, test_attribute_loc, var_loc); None }, } } +fn is_uint_prim(p: &PrimitiveType) -> bool { + matches!( + p, + PrimitiveType::U8 + | PrimitiveType::U16 + | PrimitiveType::U32 + | PrimitiveType::U64 + | PrimitiveType::U128 + | PrimitiveType::U256 + ) +} + +/// Extract a `BigInt` from any integer `MoveValue`. Used to reinterpret a +/// `u256` literal carrier into the parameter's declared width. +fn move_value_as_bigint(v: &MoveValue) -> Option { + match v { + MoveValue::U8(x) => Some(BigInt::from(*x)), + MoveValue::U16(x) => Some(BigInt::from(*x)), + MoveValue::U32(x) => Some(BigInt::from(*x)), + MoveValue::U64(x) => Some(BigInt::from(*x)), + MoveValue::U128(x) => Some(BigInt::from(*x)), + MoveValue::U256(x) => { + let mut be = x.to_le_bytes(); + be.reverse(); + Some(BigInt::from_bytes_be(Sign::Plus, &be)) + }, + _ => None, + } +} + +/// Convert `n` to a `MoveValue` of the given uint width, reporting a range +/// error (and returning `None`) when it does not fit. +fn coerce_numeric_to_width( + env: &GlobalEnv, + fn_id_loc: &Loc, + test_attribute_loc: &Loc, + var_loc: &Loc, + prim: &PrimitiveType, + n: &BigInt, +) -> Option { + let max: BigInt = match prim { + PrimitiveType::U8 => BigInt::from(u8::MAX), + PrimitiveType::U16 => BigInt::from(u16::MAX), + PrimitiveType::U32 => BigInt::from(u32::MAX), + PrimitiveType::U64 => BigInt::from(u64::MAX), + PrimitiveType::U128 => BigInt::from(u128::MAX), + PrimitiveType::U256 => (BigInt::from(1) << 256) - BigInt::from(1), + _ => return None, + }; + if n.sign() == Sign::Minus || n > &max { + env.error_with_labels(fn_id_loc, "unable to generate test", vec![ + ( + test_attribute_loc.clone(), + format!("value {} is out of range for `{:?}`", n, prim), + ), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); + return None; + } + Some(match prim { + PrimitiveType::U8 => MoveValue::U8(n.to_u64().unwrap() as u8), + PrimitiveType::U16 => MoveValue::U16(n.to_u64().unwrap() as u16), + PrimitiveType::U32 => MoveValue::U32(n.to_u64().unwrap() as u32), + PrimitiveType::U64 => MoveValue::U64(n.to_u64().unwrap()), + PrimitiveType::U128 => MoveValue::U128(n.to_u128().unwrap()), + PrimitiveType::U256 => { + let (_sign, be) = n.to_bytes_be(); + let mut buf = [0u8; 32]; + buf[32 - be.len()..].copy_from_slice(&be); + buf.reverse(); + MoveValue::U256(u256::U256::from_le_bytes(&buf)) + }, + _ => return None, + }) +} + +fn coerce_type_error(env: &GlobalEnv, fn_id_loc: &Loc, test_attribute_loc: &Loc, var_loc: &Loc) { + env.error_with_labels(fn_id_loc, "unable to generate test", vec![ + ( + test_attribute_loc.clone(), + "Unexpected argument type: expected an address, signer, bool, or integer".to_string(), + ), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); +} + //*************************************************************************** // Attribute parsers //*************************************************************************** @@ -1214,17 +1330,39 @@ fn convert_attribute_value_to_move_value( env: &GlobalEnv, value: &AttributeValue, ) -> Option { - // Only addresses are allowed + // Addresses, bools, and integer literals are accepted. Integers are carried + // as a `u256` placeholder here because the parameter's actual width is not + // known until `coerce_to_param_type` runs; coercion narrows (with a range + // check) to the real type. match value { AttributeValue::Value(_id, Value::Address(addr)) => match addr { Address::Numerical(num) => Some(*num), Address::Symbolic(sym) => env.resolve_address_alias(*sym), } .map(MoveValue::Address), + AttributeValue::Value(_id, Value::Bool(b)) => Some(MoveValue::Bool(*b)), + AttributeValue::Value(_id, Value::Number(n)) => bigint_to_u256_carrier(n), _ => None, } } +/// Carry a non-negative integer literal as a `u256` `MoveValue`. Returns `None` +/// for negative or larger-than-`u256` values (which cannot appear for a Move +/// integer literal, but are rejected defensively). +fn bigint_to_u256_carrier(n: &BigInt) -> Option { + if n.sign() == Sign::Minus { + return None; + } + let (_sign, be) = n.to_bytes_be(); + if be.len() > 32 { + return None; + } + let mut buf = [0u8; 32]; + buf[32 - be.len()..].copy_from_slice(&be); + buf.reverse(); // to little-endian for U256::from_le_bytes + Some(MoveValue::U256(u256::U256::from_le_bytes(&buf))) +} + fn check_location(env: &GlobalEnv, loc: Loc, attr: &str, location: Option) -> Option { if location.is_none() { let msg = format!( diff --git a/third_party/move/tools/move-unit-test/src/lib.rs b/third_party/move/tools/move-unit-test/src/lib.rs index 45854d5ad9d..650007358ce 100644 --- a/third_party/move/tools/move-unit-test/src/lib.rs +++ b/third_party/move/tools/move-unit-test/src/lib.rs @@ -14,7 +14,7 @@ use legacy_move_compiler::{ unit_test::TestPlan, }; use move_command_line_common::files::verify_and_create_named_address_mapping; -use legacy_move_compiler::unit_test::TestCase; +use legacy_move_compiler::unit_test::{ExpectedFailure, TestCase}; use move_compiler_v2::{ fuzz::{DefaultFuzzSource, FuzzConfig, FuzzPlanMetadata, FuzzValueSource}, fuzz_corpus, plan_builder as plan_builder_v2, @@ -187,6 +187,10 @@ impl UnitTestingConfig { &self, source_files: Vec, deps: Vec, + // Whether to replay the regression corpus into this plan. The deps-only + // pass in `build_test_plan` discards everything but files/module_info, + // so replaying there is wasted disk I/O — callers pass `false` for it. + replay_corpus: bool, ) -> Option { let addresses = verify_and_create_named_address_mapping(self.named_address_values.clone()).ok()?; @@ -225,38 +229,36 @@ impl UnitTestingConfig { // Topic 2: replay regression corpus by appending saved failing // argument vectors as extra TestCases. The runner re-runs them // before the fresh fuzz draws. - if let Some(corpus_dir) = self.fuzz_corpus_dir.as_ref() { + if let Some(corpus_dir) = self.fuzz_corpus_dir.as_ref().filter(|_| replay_corpus) { for module_plan in plans.iter_mut() { let module_id = module_plan.module_id.clone(); - // Snapshot the existing case names so we don't replay against - // already-replayed regressions. - let test_names: Vec = - module_plan.tests.keys().cloned().collect(); - for original_name in test_names { - let function_stem = original_name - .split_once('[') - .map(|(stem, _)| stem.to_string()) - .unwrap_or(original_name.clone()); - let regressions = fuzz_corpus::load_failures( - corpus_dir, - &module_id, - &function_stem, - ) - .unwrap_or_default(); + // Collect one representative `expected_failure` per real + // function symbol. Deduping by `function_name` (the real + // Move symbol, not the decorated display name) means each + // function's corpus file is read exactly once, regardless + // of how many expanded cases share it. + let mut stems: BTreeMap> = BTreeMap::new(); + for case in module_plan.tests.values() { + stems + .entry(case.function_name.clone()) + .or_insert_with(|| case.expected_failure.clone()); + } + for (stem, expected_failure) in stems { + let regressions = + fuzz_corpus::load_failures(corpus_dir, &module_id, &stem) + .unwrap_or_default(); for (i, args) in regressions.into_iter().enumerate() { - // Inherit expected_failure shape from the original - // case so abort-code expectations replay too. - let template = module_plan.tests.get(&original_name).cloned(); - let expected_failure = template - .as_ref() - .and_then(|c| c.expected_failure.clone()); - let replay_name = format!("{}#regression[{}]", function_stem, i); + let replay_name = format!("{}#regression[{}]", stem, i); module_plan.tests.insert( replay_name.clone(), TestCase { test_name: replay_name, + // Real symbol so the runner can load the + // function; the `#regression[..]` name is + // display-only. + function_name: stem.clone(), arguments: args, - expected_failure, + expected_failure: expected_failure.clone(), }, ); } @@ -279,9 +281,9 @@ impl UnitTestingConfig { let TestPlan { files, module_info, .. - } = self.compile_to_test_plan(deps.clone(), vec![])?; + } = self.compile_to_test_plan(deps.clone(), vec![], false)?; - let mut test_plan = self.compile_to_test_plan(self.source_files.clone(), deps)?; + let mut test_plan = self.compile_to_test_plan(self.source_files.clone(), deps, true)?; test_plan.module_info.extend(module_info); test_plan.files.extend(files); Some(test_plan) diff --git a/third_party/move/tools/move-unit-test/src/test_runner.rs b/third_party/move/tools/move-unit-test/src/test_runner.rs index 41f49a592f0..72470e6faa5 100644 --- a/third_party/move/tools/move-unit-test/src/test_runner.rs +++ b/third_party/move/tools/move-unit-test/src/test_runner.rs @@ -294,18 +294,17 @@ impl SharedTestingConfig { if origins.is_none() || origins.unwrap().iter().all(|o| matches!(o, ArgOrigin::Fixed)) { return; } - // The function stem is the test name without the expansion suffix. - let stem = function_name - .split_once('[') - .map(|(s, _)| s.to_string()) - .unwrap_or_else(|| function_name.to_string()); + // Key the corpus file by the real function symbol so it round-trips + // with the replay loader (which also keys by `function_name`). Parsing + // the decorated display name would break now that it carries a `#idx`. + let stem = test_info.function_name.as_str(); let args = shrunk.unwrap_or(test_info.arguments.as_slice()); // Best-effort: ignore filesystem errors so a stuck corpus path doesn't // mask the underlying test failure. let _ = move_compiler_v2::fuzz_corpus::append_failure( dir, &test_plan.module_id, - &stem, + stem, args, ); } @@ -357,6 +356,7 @@ impl SharedTestingConfig { candidate[i] = smaller; let probe = TestCase { test_name: test_info.test_name.clone(), + function_name: test_info.function_name.clone(), arguments: candidate.clone(), expected_failure: test_info.expected_failure.clone(), }; @@ -407,7 +407,11 @@ impl SharedTestingConfig { let result = module_storage .load_function( &test_plan.module_id, - IdentStr::new(function_name).unwrap(), + // Load by the real Move function symbol, NOT the (possibly + // decorated/unique) display name in `function_name` — the + // latter can contain `#`/`[`/`]`/`=` from fuzz/matrix expansion + // and is not a valid identifier. + IdentStr::new(&test_info.function_name).unwrap(), // No type args for now. &[], ) diff --git a/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs b/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs new file mode 100644 index 00000000000..6b102f76de0 --- /dev/null +++ b/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs @@ -0,0 +1,101 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +//! End-to-end coverage for fuzz-expanded `#[test]` execution. +//! +//! The compiler-side golden tests only check diagnostics; they never run the +//! Move VM. These tests build a plan AND execute it, which is the path where an +//! expanded case name (e.g. `prop#3[_x=42]`) must NOT be used as the function +//! identifier — doing so previously panicked in `IdentStr::new(..).unwrap()`. + +use move_unit_test::{test_reporter::UnitTestFactoryWithCostTable, UnitTestingConfig}; +use std::io::Write; + +/// Build a `UnitTestingConfig` for a single in-memory Move source string. +fn config_for(source: &str) -> (tempfile::TempDir, UnitTestingConfig) { + let dir = tempfile::tempdir().unwrap(); + let src = dir.path().join("fuzz_mod.move"); + let mut f = std::fs::File::create(&src).unwrap(); + f.write_all(source.as_bytes()).unwrap(); + let config = UnitTestingConfig { + num_threads: 1, + source_files: vec![src.to_str().unwrap().to_owned()], + dep_files: move_stdlib::move_stdlib_files(), + named_address_values: move_stdlib::move_stdlib_named_addresses() + .into_iter() + .collect(), + ..UnitTestingConfig::default() + }; + (dir, config) +} + +fn run(config: &UnitTestingConfig) -> (String, bool, usize) { + let plan = config.build_test_plan().expect("test plan should build"); + let total_cases: usize = plan.module_tests.values().map(|m| m.tests.len()).sum(); + let (buffer, ok) = config + .run_and_report_unit_tests( + plan, + None, + None, + Vec::new(), + UnitTestFactoryWithCostTable::new(None, None), + ) + .expect("running unit tests should not error"); + (String::from_utf8(buffer).unwrap(), ok, total_cases) +} + +const DEFAULT_FUZZ_RUNS: usize = 16; + +/// Implicit-fuzz parameters expand into `DEFAULT_FUZZ_RUNS` *uniquely named* +/// cases that all execute without panicking. Before the fix, the decorated +/// case name was fed to the VM loader and panicked; and a `bool` parameter +/// collapsed to 2 cases via map-key collision instead of staying at 16. +#[test] +fn implicit_fuzz_cases_run_without_panic() { + let (_dir, config) = config_for( + r#" +module 0x42::fuzz_mod { + #[test] + fun prop_u8(_x: u8) { } + + #[test] + fun prop_bool(_b: bool) { } +} +"#, + ); + let (output, ok, total) = run(&config); + // Two functions, each kept at the full run count thanks to unique names. + assert_eq!( + total, + 2 * DEFAULT_FUZZ_RUNS, + "each fuzz fn must expand to {} unique cases; output:\n{}", + DEFAULT_FUZZ_RUNS, + output + ); + assert!(ok, "all fuzz cases should pass; output:\n{}", output); + assert_eq!( + output.matches("[ PASS").count(), + 2 * DEFAULT_FUZZ_RUNS, + "every expanded case should report PASS; output:\n{}", + output + ); +} + +/// Explicit numeric matrices expand deterministically and run. This exercises +/// the numeric `Concrete`/`Matrix` coercion path (previously only addresses +/// were accepted). +#[test] +fn numeric_matrix_cases_run() { + let (_dir, config) = config_for( + r#" +module 0x42::fuzz_mod { + #[test(_n = [10, 20, 30])] + fun matrix_u64(_n: u64) { } +} +"#, + ); + let (output, ok, total) = run(&config); + assert_eq!(total, 3, "matrix should produce 3 cases; output:\n{}", output); + assert!(ok, "matrix cases should pass; output:\n{}", output); + assert_eq!(output.matches("[ PASS").count(), 3, "output:\n{}", output); +} From a268b6aff90676930e6e5476603e9b376b7e060b Mon Sep 17 00:00:00 2001 From: primata Date: Wed, 3 Jun 2026 15:38:34 -0300 Subject: [PATCH 5/9] remove artifact --- .../aptos-framework/boogie.shard_1.bpl | 7629 ----------------- 1 file changed, 7629 deletions(-) delete mode 100644 aptos-move/framework/aptos-framework/boogie.shard_1.bpl diff --git a/aptos-move/framework/aptos-framework/boogie.shard_1.bpl b/aptos-move/framework/aptos-framework/boogie.shard_1.bpl deleted file mode 100644 index 88ea4f0c93f..00000000000 --- a/aptos-move/framework/aptos-framework/boogie.shard_1.bpl +++ /dev/null @@ -1,7629 +0,0 @@ - -// ** Expanded prelude - -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Basic theory for vectors using arrays. This version of vectors is not extensional. - -datatype Vec { - Vec(v: [int]T, l: int) -} - -function {:builtin "MapConst"} MapConstVec(T): [int]T; -function DefaultVecElem(): T; -function {:inline} DefaultVecMap(): [int]T { MapConstVec(DefaultVecElem()) } - -function {:inline} EmptyVec(): Vec T { - Vec(DefaultVecMap(), 0) -} - -function {:inline} MakeVec1(v: T): Vec T { - Vec(DefaultVecMap()[0 := v], 1) -} - -function {:inline} MakeVec2(v1: T, v2: T): Vec T { - Vec(DefaultVecMap()[0 := v1][1 := v2], 2) -} - -function {:inline} MakeVec3(v1: T, v2: T, v3: T): Vec T { - Vec(DefaultVecMap()[0 := v1][1 := v2][2 := v3], 3) -} - -function {:inline} MakeVec4(v1: T, v2: T, v3: T, v4: T): Vec T { - Vec(DefaultVecMap()[0 := v1][1 := v2][2 := v3][3 := v4], 4) -} - -function {:inline} ExtendVec(v: Vec T, elem: T): Vec T { - (var l := v->l; - Vec(v->v[l := elem], l + 1)) -} - -function {:inline} ReadVec(v: Vec T, i: int): T { - v->v[i] -} - -function {:inline} LenVec(v: Vec T): int { - v->l -} - -function {:inline} IsEmptyVec(v: Vec T): bool { - v->l == 0 -} - -function {:inline} RemoveVec(v: Vec T): Vec T { - (var l := v->l - 1; - Vec(v->v[l := DefaultVecElem()], l)) -} - -function {:inline} RemoveAtVec(v: Vec T, i: int): Vec T { - (var l := v->l - 1; - Vec( - (lambda j: int :: - if j >= 0 && j < l then - if j < i then v->v[j] else v->v[j+1] - else DefaultVecElem()), - l)) -} - -function {:inline} ConcatVec(v1: Vec T, v2: Vec T): Vec T { - (var l1, m1, l2, m2 := v1->l, v1->v, v2->l, v2->v; - Vec( - (lambda i: int :: - if i >= 0 && i < l1 + l2 then - if i < l1 then m1[i] else m2[i - l1] - else DefaultVecElem()), - l1 + l2)) -} - -function {:inline} ReverseVec(v: Vec T): Vec T { - (var l := v->l; - Vec( - (lambda i: int :: if 0 <= i && i < l then v->v[l - i - 1] else DefaultVecElem()), - l)) -} - -function {:inline} SliceVec(v: Vec T, i: int, j: int): Vec T { - (var m := v->v; - Vec( - (lambda k:int :: - if 0 <= k && k < j - i then - m[i + k] - else - DefaultVecElem()), - (if j - i < 0 then 0 else j - i))) -} - - -function {:inline} UpdateVec(v: Vec T, i: int, elem: T): Vec T { - Vec(v->v[i := elem], v->l) -} - -function {:inline} SwapVec(v: Vec T, i: int, j: int): Vec T { - (var m := v->v; - Vec(m[i := m[j]][j := m[i]], v->l)) -} - -function {:inline} ContainsVec(v: Vec T, e: T): bool { - (var l := v->l; - (exists i: int :: InRangeVec(v, i) && v->v[i] == e)) -} - -function IndexOfVec(v: Vec T, e: T): int; -axiom {:ctor "Vec"} (forall v: Vec T, e: T :: {IndexOfVec(v, e)} - (var i := IndexOfVec(v,e); - if (!ContainsVec(v, e)) then i == -1 - else InRangeVec(v, i) && ReadVec(v, i) == e && - (forall j: int :: j >= 0 && j < i ==> ReadVec(v, j) != e))); - -// This function should stay non-inlined as it guards many quantifiers -// over vectors. It appears important to have this uninterpreted for -// quantifier triggering. -function InRangeVec(v: Vec T, i: int): bool { - i >= 0 && i < LenVec(v) -} - -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Boogie model for multisets, based on Boogie arrays. This theory assumes extensional equality for element types. - -datatype Multiset { - Multiset(v: [T]int, l: int) -} - -function {:builtin "MapConst"} MapConstMultiset(l: int): [T]int; - -function {:inline} EmptyMultiset(): Multiset T { - Multiset(MapConstMultiset(0), 0) -} - -function {:inline} LenMultiset(s: Multiset T): int { - s->l -} - -function {:inline} ExtendMultiset(s: Multiset T, v: T): Multiset T { - (var len := s->l; - (var cnt := s->v[v]; - Multiset(s->v[v := (cnt + 1)], len + 1))) -} - -// This function returns (s1 - s2). This function assumes that s2 is a subset of s1. -function {:inline} SubtractMultiset(s1: Multiset T, s2: Multiset T): Multiset T { - (var len1 := s1->l; - (var len2 := s2->l; - Multiset((lambda v:T :: s1->v[v]-s2->v[v]), len1-len2))) -} - -function {:inline} IsEmptyMultiset(s: Multiset T): bool { - (s->l == 0) && - (forall v: T :: s->v[v] == 0) -} - -function {:inline} IsSubsetMultiset(s1: Multiset T, s2: Multiset T): bool { - (s1->l <= s2->l) && - (forall v: T :: s1->v[v] <= s2->v[v]) -} - -function {:inline} ContainsMultiset(s: Multiset T, v: T): bool { - s->v[v] > 0 -} - -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Theory for tables. - -// v is the SMT array holding the key-value assignment. e is an array which -// independently determines whether a key is valid or not. l is the length. -// -// Note that even though the program cannot reflect over existence of a key, -// we want the specification to be able to do this, so it can express -// verification conditions like "key has been inserted". -datatype Table { - Table(v: [K]V, e: [K]bool, l: int) -} - -// Functions for default SMT arrays. For the table values, we don't care and -// use an uninterpreted function. -function DefaultTableArray(): [K]V; -function DefaultTableKeyExistsArray(): [K]bool; -axiom DefaultTableKeyExistsArray() == (lambda i: int :: false); - -function {:inline} EmptyTable(): Table K V { - Table(DefaultTableArray(), DefaultTableKeyExistsArray(), 0) -} - -function {:inline} GetTable(t: Table K V, k: K): V { - // Notice we do not check whether key is in the table. The result is undetermined if it is not. - t->v[k] -} - -function {:inline} LenTable(t: Table K V): int { - t->l -} - - -function {:inline} ContainsTable(t: Table K V, k: K): bool { - t->e[k] -} - -function {:inline} UpdateTable(t: Table K V, k: K, v: V): Table K V { - Table(t->v[k := v], t->e, t->l) -} - -function {:inline} AddTable(t: Table K V, k: K, v: V): Table K V { - // This function has an undetermined result if the key is already in the table - // (all specification functions have this "partial definiteness" behavior). Thus we can - // just increment the length. - Table(t->v[k := v], t->e[k := true], t->l + 1) -} - -function {:inline} RemoveTable(t: Table K V, k: K): Table K V { - // Similar as above, we only need to consider the case where the key is in the table. - Table(t->v, t->e[k := false], t->l - 1) -} - -axiom {:ctor "Table"} (forall t: Table K V :: {LenTable(t)} - (exists k: K :: {ContainsTable(t, k)} ContainsTable(t, k)) ==> LenTable(t) >= 1 -); -// TODO: we might want to encoder a stronger property that the length of table -// must be more than N given a set of N items. Currently we don't see a need here -// and the above axiom seems to be sufficient. -// Copyright © Aptos Foundation -// SPDX-License-Identifier: Apache-2.0 - -// ================================================================================== -// Native object::exists_at - -// ================================================================================== -// Intrinsic implementation of aggregator and aggregator factory - -datatype $1_aggregator_Aggregator { - $1_aggregator_Aggregator($handle: int, $key: int, $limit: int, $val: int) -} -function {:inline} $Update'$1_aggregator_Aggregator'_handle(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { - $1_aggregator_Aggregator(x, s->$key, s->$limit, s->$val) -} -function {:inline} $Update'$1_aggregator_Aggregator'_key(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { - $1_aggregator_Aggregator(s->$handle, x, s->$limit, s->$val) -} -function {:inline} $Update'$1_aggregator_Aggregator'_limit(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { - $1_aggregator_Aggregator(s->$handle, s->$key, x, s->$val) -} -function {:inline} $Update'$1_aggregator_Aggregator'_val(s: $1_aggregator_Aggregator, x: int): $1_aggregator_Aggregator { - $1_aggregator_Aggregator(s->$handle, s->$key, s->$limit, x) -} -function $IsValid'$1_aggregator_Aggregator'(s: $1_aggregator_Aggregator): bool { - $IsValid'address'(s->$handle) - && $IsValid'address'(s->$key) - && $IsValid'u128'(s->$limit) - && $IsValid'u128'(s->$val) -} -function {:inline} $IsEqual'$1_aggregator_Aggregator'(s1: $1_aggregator_Aggregator, s2: $1_aggregator_Aggregator): bool { - s1 == s2 -} -function {:inline} $1_aggregator_spec_get_limit(s: $1_aggregator_Aggregator): int { - s->$limit -} -function {:inline} $1_aggregator_limit(s: $1_aggregator_Aggregator): int { - s->$limit -} -procedure {:inline 1} $1_aggregator_limit(s: $1_aggregator_Aggregator) returns (res: int) { - res := s->$limit; - return; -} -function {:inline} $1_aggregator_spec_get_handle(s: $1_aggregator_Aggregator): int { - s->$handle -} -function {:inline} $1_aggregator_spec_get_key(s: $1_aggregator_Aggregator): int { - s->$key -} -function {:inline} $1_aggregator_spec_get_val(s: $1_aggregator_Aggregator): int { - s->$val -} - -function $1_aggregator_spec_read(agg: $1_aggregator_Aggregator): int { - $1_aggregator_spec_get_val(agg) -} - -function $1_aggregator_spec_aggregator_set_val(agg: $1_aggregator_Aggregator, val: int): $1_aggregator_Aggregator { - $Update'$1_aggregator_Aggregator'_val(agg, val) -} - -function $1_aggregator_spec_aggregator_get_val(agg: $1_aggregator_Aggregator): int { - $1_aggregator_spec_get_val(agg) -} - -function $1_aggregator_factory_spec_new_aggregator(limit: int) : $1_aggregator_Aggregator; - -axiom (forall limit: int :: {$1_aggregator_factory_spec_new_aggregator(limit)} - (var agg := $1_aggregator_factory_spec_new_aggregator(limit); - $1_aggregator_spec_get_limit(agg) == limit)); - -axiom (forall limit: int :: {$1_aggregator_factory_spec_new_aggregator(limit)} - (var agg := $1_aggregator_factory_spec_new_aggregator(limit); - $1_aggregator_spec_aggregator_get_val(agg) == 0)); - -// ================================================================================== -// Native for function_info - -procedure $1_function_info_is_identifier(s: Vec int) returns (res: bool); - - - -// Uninterpreted function for all types - -function $Arbitrary_value_of'#0'(): #0; - -function $Arbitrary_value_of'$1_account_Account'(): $1_account_Account; - -function $Arbitrary_value_of'$1_account_CapabilityOffer'$1_account_RotationCapability''(): $1_account_CapabilityOffer'$1_account_RotationCapability'; - -function $Arbitrary_value_of'$1_account_CapabilityOffer'$1_account_SignerCapability''(): $1_account_CapabilityOffer'$1_account_SignerCapability'; - -function $Arbitrary_value_of'$1_account_SignerCapability'(): $1_account_SignerCapability; - -function $Arbitrary_value_of'$1_chain_status_GenesisEndMarker'(): $1_chain_status_GenesisEndMarker; - -function $Arbitrary_value_of'$1_event_EventHandle'$1_account_CoinRegisterEvent''(): $1_event_EventHandle'$1_account_CoinRegisterEvent'; - -function $Arbitrary_value_of'$1_event_EventHandle'$1_account_KeyRotationEvent''(): $1_event_EventHandle'$1_account_KeyRotationEvent'; - -function $Arbitrary_value_of'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'; - -function $Arbitrary_value_of'$1_features_Features'(): $1_features_Features; - -function $Arbitrary_value_of'$1_guid_GUID'(): $1_guid_GUID; - -function $Arbitrary_value_of'$1_guid_ID'(): $1_guid_ID; - -function $Arbitrary_value_of'$1_option_Option'address''(): $1_option_Option'address'; - -function $Arbitrary_value_of'$1_permissioned_signer_GrantedPermissionHandles'(): $1_permissioned_signer_GrantedPermissionHandles; - -function $Arbitrary_value_of'$1_reconfiguration_Configuration'(): $1_reconfiguration_Configuration; - -function $Arbitrary_value_of'$1_timelock_AddCreators'(): $1_timelock_AddCreators; - -function $Arbitrary_value_of'$1_timelock_AddExecutors'(): $1_timelock_AddExecutors; - -function $Arbitrary_value_of'$1_timelock_CancelTransaction'(): $1_timelock_CancelTransaction; - -function $Arbitrary_value_of'$1_timelock_CreateTransaction'(): $1_timelock_CreateTransaction; - -function $Arbitrary_value_of'$1_timelock_RemoveCreators'(): $1_timelock_RemoveCreators; - -function $Arbitrary_value_of'$1_timelock_RemoveExecutors'(): $1_timelock_RemoveExecutors; - -function $Arbitrary_value_of'$1_timelock_TimelockAccount'(): $1_timelock_TimelockAccount; - -function $Arbitrary_value_of'$1_timelock_TimelockTransaction'(): $1_timelock_TimelockTransaction; - -function $Arbitrary_value_of'$1_timelock_UpdateMinNumSecondsExecute'(): $1_timelock_UpdateMinNumSecondsExecute; - -function $Arbitrary_value_of'$1_timestamp_CurrentTimeMicroseconds'(): $1_timestamp_CurrentTimeMicroseconds; - -function $Arbitrary_value_of'$1_type_info_TypeInfo'(): $1_type_info_TypeInfo; - -function $Arbitrary_value_of'signer'(): $signer; - -function $Arbitrary_value_of'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(): Table int ($1_timelock_TimelockTransaction); - -function $Arbitrary_value_of'vec'#0''(): Vec (#0); - -function $Arbitrary_value_of'vec'address''(): Vec (int); - -function $Arbitrary_value_of'vec'u8''(): Vec (int); - -function $Arbitrary_value_of'bool'(): bool; - -function $Arbitrary_value_of'address'(): int; - -function $Arbitrary_value_of'u256'(): int; - -function $Arbitrary_value_of'u64'(): int; - -function $Arbitrary_value_of'u8'(): int; - -function $Arbitrary_value_of'vec'bv8''(): Vec (bv8); - -function $Arbitrary_value_of'bv256'(): bv256; - -function $Arbitrary_value_of'bv64'(): bv64; - -function $Arbitrary_value_of'bv8'(): bv8; - - - -// ============================================================================================ -// Primitive Types - -const $MAX_U8: int; -axiom $MAX_U8 == 255; -const $MAX_U16: int; -axiom $MAX_U16 == 65535; -const $MAX_U32: int; -axiom $MAX_U32 == 4294967295; -const $MAX_U64: int; -axiom $MAX_U64 == 18446744073709551615; -const $MAX_U128: int; -axiom $MAX_U128 == 340282366920938463463374607431768211455; -const $MAX_U256: int; -axiom $MAX_U256 == 115792089237316195423570985008687907853269984665640564039457584007913129639935; - -// Templates for bitvector operations - -function {:bvbuiltin "bvand"} $And'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvor"} $Or'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvxor"} $Xor'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvadd"} $Add'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvsub"} $Sub'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvmul"} $Mul'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvudiv"} $Div'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvurem"} $Mod'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvshl"} $Shl'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvlshr"} $Shr'Bv8'(bv8,bv8) returns(bv8); -function {:bvbuiltin "bvult"} $Lt'Bv8'(bv8,bv8) returns(bool); -function {:bvbuiltin "bvule"} $Le'Bv8'(bv8,bv8) returns(bool); -function {:bvbuiltin "bvugt"} $Gt'Bv8'(bv8,bv8) returns(bool); -function {:bvbuiltin "bvuge"} $Ge'Bv8'(bv8,bv8) returns(bool); - -procedure {:inline 1} $AddBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if ($Lt'Bv8'($Add'Bv8'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Add'Bv8'(src1, src2); -} - -procedure {:inline 1} $AddBv8_unchecked(src1: bv8, src2: bv8) returns (dst: bv8) -{ - dst := $Add'Bv8'(src1, src2); -} - -procedure {:inline 1} $SubBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if ($Lt'Bv8'(src1, src2)) { - call $ExecFailureAbort(); - return; - } - dst := $Sub'Bv8'(src1, src2); -} - -procedure {:inline 1} $MulBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if ($Lt'Bv8'($Mul'Bv8'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Mul'Bv8'(src1, src2); -} - -procedure {:inline 1} $DivBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if (src2 == 0bv8) { - call $ExecFailureAbort(); - return; - } - dst := $Div'Bv8'(src1, src2); -} - -procedure {:inline 1} $ModBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if (src2 == 0bv8) { - call $ExecFailureAbort(); - return; - } - dst := $Mod'Bv8'(src1, src2); -} - -procedure {:inline 1} $AndBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - dst := $And'Bv8'(src1,src2); -} - -procedure {:inline 1} $OrBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - dst := $Or'Bv8'(src1,src2); -} - -procedure {:inline 1} $XorBv8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - dst := $Xor'Bv8'(src1,src2); -} - -procedure {:inline 1} $LtBv8(src1: bv8, src2: bv8) returns (dst: bool) -{ - dst := $Lt'Bv8'(src1,src2); -} - -procedure {:inline 1} $LeBv8(src1: bv8, src2: bv8) returns (dst: bool) -{ - dst := $Le'Bv8'(src1,src2); -} - -procedure {:inline 1} $GtBv8(src1: bv8, src2: bv8) returns (dst: bool) -{ - dst := $Gt'Bv8'(src1,src2); -} - -procedure {:inline 1} $GeBv8(src1: bv8, src2: bv8) returns (dst: bool) -{ - dst := $Ge'Bv8'(src1,src2); -} - -function $IsValid'bv8'(v: bv8): bool { - $Ge'Bv8'(v,0bv8) && $Le'Bv8'(v,255bv8) -} - -function {:inline} $IsEqual'bv8'(x: bv8, y: bv8): bool { - x == y -} - -procedure {:inline 1} $int2bv8(src: int) returns (dst: bv8) -{ - if (src > 255) { - call $ExecFailureAbort(); - return; - } - dst := $int2bv.8(src); -} - -procedure {:inline 1} $bv2int8(src: bv8) returns (dst: int) -{ - dst := $bv2int.8(src); -} - -function {:builtin "(_ int2bv 8)"} $int2bv.8(i: int) returns (bv8); -function {:builtin "bv2nat"} $bv2int.8(i: bv8) returns (int); - -function {:bvbuiltin "bvand"} $And'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvor"} $Or'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvxor"} $Xor'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvadd"} $Add'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvsub"} $Sub'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvmul"} $Mul'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvudiv"} $Div'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvurem"} $Mod'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvshl"} $Shl'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvlshr"} $Shr'Bv16'(bv16,bv16) returns(bv16); -function {:bvbuiltin "bvult"} $Lt'Bv16'(bv16,bv16) returns(bool); -function {:bvbuiltin "bvule"} $Le'Bv16'(bv16,bv16) returns(bool); -function {:bvbuiltin "bvugt"} $Gt'Bv16'(bv16,bv16) returns(bool); -function {:bvbuiltin "bvuge"} $Ge'Bv16'(bv16,bv16) returns(bool); - -procedure {:inline 1} $AddBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if ($Lt'Bv16'($Add'Bv16'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Add'Bv16'(src1, src2); -} - -procedure {:inline 1} $AddBv16_unchecked(src1: bv16, src2: bv16) returns (dst: bv16) -{ - dst := $Add'Bv16'(src1, src2); -} - -procedure {:inline 1} $SubBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if ($Lt'Bv16'(src1, src2)) { - call $ExecFailureAbort(); - return; - } - dst := $Sub'Bv16'(src1, src2); -} - -procedure {:inline 1} $MulBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if ($Lt'Bv16'($Mul'Bv16'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Mul'Bv16'(src1, src2); -} - -procedure {:inline 1} $DivBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if (src2 == 0bv16) { - call $ExecFailureAbort(); - return; - } - dst := $Div'Bv16'(src1, src2); -} - -procedure {:inline 1} $ModBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if (src2 == 0bv16) { - call $ExecFailureAbort(); - return; - } - dst := $Mod'Bv16'(src1, src2); -} - -procedure {:inline 1} $AndBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - dst := $And'Bv16'(src1,src2); -} - -procedure {:inline 1} $OrBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - dst := $Or'Bv16'(src1,src2); -} - -procedure {:inline 1} $XorBv16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - dst := $Xor'Bv16'(src1,src2); -} - -procedure {:inline 1} $LtBv16(src1: bv16, src2: bv16) returns (dst: bool) -{ - dst := $Lt'Bv16'(src1,src2); -} - -procedure {:inline 1} $LeBv16(src1: bv16, src2: bv16) returns (dst: bool) -{ - dst := $Le'Bv16'(src1,src2); -} - -procedure {:inline 1} $GtBv16(src1: bv16, src2: bv16) returns (dst: bool) -{ - dst := $Gt'Bv16'(src1,src2); -} - -procedure {:inline 1} $GeBv16(src1: bv16, src2: bv16) returns (dst: bool) -{ - dst := $Ge'Bv16'(src1,src2); -} - -function $IsValid'bv16'(v: bv16): bool { - $Ge'Bv16'(v,0bv16) && $Le'Bv16'(v,65535bv16) -} - -function {:inline} $IsEqual'bv16'(x: bv16, y: bv16): bool { - x == y -} - -procedure {:inline 1} $int2bv16(src: int) returns (dst: bv16) -{ - if (src > 65535) { - call $ExecFailureAbort(); - return; - } - dst := $int2bv.16(src); -} - -procedure {:inline 1} $bv2int16(src: bv16) returns (dst: int) -{ - dst := $bv2int.16(src); -} - -function {:builtin "(_ int2bv 16)"} $int2bv.16(i: int) returns (bv16); -function {:builtin "bv2nat"} $bv2int.16(i: bv16) returns (int); - -function {:bvbuiltin "bvand"} $And'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvor"} $Or'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvxor"} $Xor'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvadd"} $Add'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvsub"} $Sub'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvmul"} $Mul'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvudiv"} $Div'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvurem"} $Mod'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvshl"} $Shl'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvlshr"} $Shr'Bv32'(bv32,bv32) returns(bv32); -function {:bvbuiltin "bvult"} $Lt'Bv32'(bv32,bv32) returns(bool); -function {:bvbuiltin "bvule"} $Le'Bv32'(bv32,bv32) returns(bool); -function {:bvbuiltin "bvugt"} $Gt'Bv32'(bv32,bv32) returns(bool); -function {:bvbuiltin "bvuge"} $Ge'Bv32'(bv32,bv32) returns(bool); - -procedure {:inline 1} $AddBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if ($Lt'Bv32'($Add'Bv32'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Add'Bv32'(src1, src2); -} - -procedure {:inline 1} $AddBv32_unchecked(src1: bv32, src2: bv32) returns (dst: bv32) -{ - dst := $Add'Bv32'(src1, src2); -} - -procedure {:inline 1} $SubBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if ($Lt'Bv32'(src1, src2)) { - call $ExecFailureAbort(); - return; - } - dst := $Sub'Bv32'(src1, src2); -} - -procedure {:inline 1} $MulBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if ($Lt'Bv32'($Mul'Bv32'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Mul'Bv32'(src1, src2); -} - -procedure {:inline 1} $DivBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if (src2 == 0bv32) { - call $ExecFailureAbort(); - return; - } - dst := $Div'Bv32'(src1, src2); -} - -procedure {:inline 1} $ModBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if (src2 == 0bv32) { - call $ExecFailureAbort(); - return; - } - dst := $Mod'Bv32'(src1, src2); -} - -procedure {:inline 1} $AndBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - dst := $And'Bv32'(src1,src2); -} - -procedure {:inline 1} $OrBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - dst := $Or'Bv32'(src1,src2); -} - -procedure {:inline 1} $XorBv32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - dst := $Xor'Bv32'(src1,src2); -} - -procedure {:inline 1} $LtBv32(src1: bv32, src2: bv32) returns (dst: bool) -{ - dst := $Lt'Bv32'(src1,src2); -} - -procedure {:inline 1} $LeBv32(src1: bv32, src2: bv32) returns (dst: bool) -{ - dst := $Le'Bv32'(src1,src2); -} - -procedure {:inline 1} $GtBv32(src1: bv32, src2: bv32) returns (dst: bool) -{ - dst := $Gt'Bv32'(src1,src2); -} - -procedure {:inline 1} $GeBv32(src1: bv32, src2: bv32) returns (dst: bool) -{ - dst := $Ge'Bv32'(src1,src2); -} - -function $IsValid'bv32'(v: bv32): bool { - $Ge'Bv32'(v,0bv32) && $Le'Bv32'(v,2147483647bv32) -} - -function {:inline} $IsEqual'bv32'(x: bv32, y: bv32): bool { - x == y -} - -procedure {:inline 1} $int2bv32(src: int) returns (dst: bv32) -{ - if (src > 2147483647) { - call $ExecFailureAbort(); - return; - } - dst := $int2bv.32(src); -} - -procedure {:inline 1} $bv2int32(src: bv32) returns (dst: int) -{ - dst := $bv2int.32(src); -} - -function {:builtin "(_ int2bv 32)"} $int2bv.32(i: int) returns (bv32); -function {:builtin "bv2nat"} $bv2int.32(i: bv32) returns (int); - -function {:bvbuiltin "bvand"} $And'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvor"} $Or'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvxor"} $Xor'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvadd"} $Add'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvsub"} $Sub'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvmul"} $Mul'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvudiv"} $Div'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvurem"} $Mod'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvshl"} $Shl'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvlshr"} $Shr'Bv64'(bv64,bv64) returns(bv64); -function {:bvbuiltin "bvult"} $Lt'Bv64'(bv64,bv64) returns(bool); -function {:bvbuiltin "bvule"} $Le'Bv64'(bv64,bv64) returns(bool); -function {:bvbuiltin "bvugt"} $Gt'Bv64'(bv64,bv64) returns(bool); -function {:bvbuiltin "bvuge"} $Ge'Bv64'(bv64,bv64) returns(bool); - -procedure {:inline 1} $AddBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if ($Lt'Bv64'($Add'Bv64'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Add'Bv64'(src1, src2); -} - -procedure {:inline 1} $AddBv64_unchecked(src1: bv64, src2: bv64) returns (dst: bv64) -{ - dst := $Add'Bv64'(src1, src2); -} - -procedure {:inline 1} $SubBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if ($Lt'Bv64'(src1, src2)) { - call $ExecFailureAbort(); - return; - } - dst := $Sub'Bv64'(src1, src2); -} - -procedure {:inline 1} $MulBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if ($Lt'Bv64'($Mul'Bv64'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Mul'Bv64'(src1, src2); -} - -procedure {:inline 1} $DivBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if (src2 == 0bv64) { - call $ExecFailureAbort(); - return; - } - dst := $Div'Bv64'(src1, src2); -} - -procedure {:inline 1} $ModBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if (src2 == 0bv64) { - call $ExecFailureAbort(); - return; - } - dst := $Mod'Bv64'(src1, src2); -} - -procedure {:inline 1} $AndBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - dst := $And'Bv64'(src1,src2); -} - -procedure {:inline 1} $OrBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - dst := $Or'Bv64'(src1,src2); -} - -procedure {:inline 1} $XorBv64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - dst := $Xor'Bv64'(src1,src2); -} - -procedure {:inline 1} $LtBv64(src1: bv64, src2: bv64) returns (dst: bool) -{ - dst := $Lt'Bv64'(src1,src2); -} - -procedure {:inline 1} $LeBv64(src1: bv64, src2: bv64) returns (dst: bool) -{ - dst := $Le'Bv64'(src1,src2); -} - -procedure {:inline 1} $GtBv64(src1: bv64, src2: bv64) returns (dst: bool) -{ - dst := $Gt'Bv64'(src1,src2); -} - -procedure {:inline 1} $GeBv64(src1: bv64, src2: bv64) returns (dst: bool) -{ - dst := $Ge'Bv64'(src1,src2); -} - -function $IsValid'bv64'(v: bv64): bool { - $Ge'Bv64'(v,0bv64) && $Le'Bv64'(v,18446744073709551615bv64) -} - -function {:inline} $IsEqual'bv64'(x: bv64, y: bv64): bool { - x == y -} - -procedure {:inline 1} $int2bv64(src: int) returns (dst: bv64) -{ - if (src > 18446744073709551615) { - call $ExecFailureAbort(); - return; - } - dst := $int2bv.64(src); -} - -procedure {:inline 1} $bv2int64(src: bv64) returns (dst: int) -{ - dst := $bv2int.64(src); -} - -function {:builtin "(_ int2bv 64)"} $int2bv.64(i: int) returns (bv64); -function {:builtin "bv2nat"} $bv2int.64(i: bv64) returns (int); - -function {:bvbuiltin "bvand"} $And'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvor"} $Or'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvxor"} $Xor'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvadd"} $Add'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvsub"} $Sub'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvmul"} $Mul'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvudiv"} $Div'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvurem"} $Mod'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvshl"} $Shl'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvlshr"} $Shr'Bv128'(bv128,bv128) returns(bv128); -function {:bvbuiltin "bvult"} $Lt'Bv128'(bv128,bv128) returns(bool); -function {:bvbuiltin "bvule"} $Le'Bv128'(bv128,bv128) returns(bool); -function {:bvbuiltin "bvugt"} $Gt'Bv128'(bv128,bv128) returns(bool); -function {:bvbuiltin "bvuge"} $Ge'Bv128'(bv128,bv128) returns(bool); - -procedure {:inline 1} $AddBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if ($Lt'Bv128'($Add'Bv128'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Add'Bv128'(src1, src2); -} - -procedure {:inline 1} $AddBv128_unchecked(src1: bv128, src2: bv128) returns (dst: bv128) -{ - dst := $Add'Bv128'(src1, src2); -} - -procedure {:inline 1} $SubBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if ($Lt'Bv128'(src1, src2)) { - call $ExecFailureAbort(); - return; - } - dst := $Sub'Bv128'(src1, src2); -} - -procedure {:inline 1} $MulBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if ($Lt'Bv128'($Mul'Bv128'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Mul'Bv128'(src1, src2); -} - -procedure {:inline 1} $DivBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if (src2 == 0bv128) { - call $ExecFailureAbort(); - return; - } - dst := $Div'Bv128'(src1, src2); -} - -procedure {:inline 1} $ModBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if (src2 == 0bv128) { - call $ExecFailureAbort(); - return; - } - dst := $Mod'Bv128'(src1, src2); -} - -procedure {:inline 1} $AndBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - dst := $And'Bv128'(src1,src2); -} - -procedure {:inline 1} $OrBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - dst := $Or'Bv128'(src1,src2); -} - -procedure {:inline 1} $XorBv128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - dst := $Xor'Bv128'(src1,src2); -} - -procedure {:inline 1} $LtBv128(src1: bv128, src2: bv128) returns (dst: bool) -{ - dst := $Lt'Bv128'(src1,src2); -} - -procedure {:inline 1} $LeBv128(src1: bv128, src2: bv128) returns (dst: bool) -{ - dst := $Le'Bv128'(src1,src2); -} - -procedure {:inline 1} $GtBv128(src1: bv128, src2: bv128) returns (dst: bool) -{ - dst := $Gt'Bv128'(src1,src2); -} - -procedure {:inline 1} $GeBv128(src1: bv128, src2: bv128) returns (dst: bool) -{ - dst := $Ge'Bv128'(src1,src2); -} - -function $IsValid'bv128'(v: bv128): bool { - $Ge'Bv128'(v,0bv128) && $Le'Bv128'(v,340282366920938463463374607431768211455bv128) -} - -function {:inline} $IsEqual'bv128'(x: bv128, y: bv128): bool { - x == y -} - -procedure {:inline 1} $int2bv128(src: int) returns (dst: bv128) -{ - if (src > 340282366920938463463374607431768211455) { - call $ExecFailureAbort(); - return; - } - dst := $int2bv.128(src); -} - -procedure {:inline 1} $bv2int128(src: bv128) returns (dst: int) -{ - dst := $bv2int.128(src); -} - -function {:builtin "(_ int2bv 128)"} $int2bv.128(i: int) returns (bv128); -function {:builtin "bv2nat"} $bv2int.128(i: bv128) returns (int); - -function {:bvbuiltin "bvand"} $And'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvor"} $Or'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvxor"} $Xor'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvadd"} $Add'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvsub"} $Sub'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvmul"} $Mul'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvudiv"} $Div'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvurem"} $Mod'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvshl"} $Shl'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvlshr"} $Shr'Bv256'(bv256,bv256) returns(bv256); -function {:bvbuiltin "bvult"} $Lt'Bv256'(bv256,bv256) returns(bool); -function {:bvbuiltin "bvule"} $Le'Bv256'(bv256,bv256) returns(bool); -function {:bvbuiltin "bvugt"} $Gt'Bv256'(bv256,bv256) returns(bool); -function {:bvbuiltin "bvuge"} $Ge'Bv256'(bv256,bv256) returns(bool); - -procedure {:inline 1} $AddBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if ($Lt'Bv256'($Add'Bv256'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Add'Bv256'(src1, src2); -} - -procedure {:inline 1} $AddBv256_unchecked(src1: bv256, src2: bv256) returns (dst: bv256) -{ - dst := $Add'Bv256'(src1, src2); -} - -procedure {:inline 1} $SubBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if ($Lt'Bv256'(src1, src2)) { - call $ExecFailureAbort(); - return; - } - dst := $Sub'Bv256'(src1, src2); -} - -procedure {:inline 1} $MulBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if ($Lt'Bv256'($Mul'Bv256'(src1, src2), src1)) { - call $ExecFailureAbort(); - return; - } - dst := $Mul'Bv256'(src1, src2); -} - -procedure {:inline 1} $DivBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if (src2 == 0bv256) { - call $ExecFailureAbort(); - return; - } - dst := $Div'Bv256'(src1, src2); -} - -procedure {:inline 1} $ModBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if (src2 == 0bv256) { - call $ExecFailureAbort(); - return; - } - dst := $Mod'Bv256'(src1, src2); -} - -procedure {:inline 1} $AndBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - dst := $And'Bv256'(src1,src2); -} - -procedure {:inline 1} $OrBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - dst := $Or'Bv256'(src1,src2); -} - -procedure {:inline 1} $XorBv256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - dst := $Xor'Bv256'(src1,src2); -} - -procedure {:inline 1} $LtBv256(src1: bv256, src2: bv256) returns (dst: bool) -{ - dst := $Lt'Bv256'(src1,src2); -} - -procedure {:inline 1} $LeBv256(src1: bv256, src2: bv256) returns (dst: bool) -{ - dst := $Le'Bv256'(src1,src2); -} - -procedure {:inline 1} $GtBv256(src1: bv256, src2: bv256) returns (dst: bool) -{ - dst := $Gt'Bv256'(src1,src2); -} - -procedure {:inline 1} $GeBv256(src1: bv256, src2: bv256) returns (dst: bool) -{ - dst := $Ge'Bv256'(src1,src2); -} - -function $IsValid'bv256'(v: bv256): bool { - $Ge'Bv256'(v,0bv256) && $Le'Bv256'(v,115792089237316195423570985008687907853269984665640564039457584007913129639935bv256) -} - -function {:inline} $IsEqual'bv256'(x: bv256, y: bv256): bool { - x == y -} - -procedure {:inline 1} $int2bv256(src: int) returns (dst: bv256) -{ - if (src > 115792089237316195423570985008687907853269984665640564039457584007913129639935) { - call $ExecFailureAbort(); - return; - } - dst := $int2bv.256(src); -} - -procedure {:inline 1} $bv2int256(src: bv256) returns (dst: int) -{ - dst := $bv2int.256(src); -} - -function {:builtin "(_ int2bv 256)"} $int2bv.256(i: int) returns (bv256); -function {:builtin "bv2nat"} $bv2int.256(i: bv256) returns (int); - -datatype $Range { - $Range(lb: int, ub: int) -} - -function {:inline} $IsValid'bool'(v: bool): bool { - true -} - -function $IsValid'u8'(v: int): bool { - v >= 0 && v <= $MAX_U8 -} - -function $IsValid'u16'(v: int): bool { - v >= 0 && v <= $MAX_U16 -} - -function $IsValid'u32'(v: int): bool { - v >= 0 && v <= $MAX_U32 -} - -function $IsValid'u64'(v: int): bool { - v >= 0 && v <= $MAX_U64 -} - -function $IsValid'u128'(v: int): bool { - v >= 0 && v <= $MAX_U128 -} - -function $IsValid'u256'(v: int): bool { - v >= 0 && v <= $MAX_U256 -} - -function $IsValid'num'(v: int): bool { - true -} - -function $IsValid'address'(v: int): bool { - // TODO: restrict max to representable addresses? - v >= 0 -} - -function {:inline} $IsValidRange(r: $Range): bool { - $IsValid'u64'(r->lb) && $IsValid'u64'(r->ub) -} - -// Intentionally not inlined so it serves as a trigger in quantifiers. -function $InRange(r: $Range, i: int): bool { - r->lb <= i && i < r->ub -} - - -function {:inline} $IsEqual'u8'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'u16'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'u32'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'u64'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'u128'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'u256'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'num'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'address'(x: int, y: int): bool { - x == y -} - -function {:inline} $IsEqual'bool'(x: bool, y: bool): bool { - x == y -} - -// ============================================================================================ -// Memory - -datatype $Location { - // A global resource location within the statically known resource type's memory, - // where `a` is an address. - $Global(a: int), - // A local location. `i` is the unique index of the local. - $Local(i: int), - // The location of a reference outside of the verification scope, for example, a `&mut` parameter - // of the function being verified. References with these locations don't need to be written back - // when mutation ends. - $Param(i: int), - // The location of an uninitialized mutation. Using this to make sure that the location - // will not be equal to any valid mutation locations, i.e., $Local, $Global, or $Param. - $Uninitialized() -} - -// A mutable reference which also carries its current value. Since mutable references -// are single threaded in Move, we can keep them together and treat them as a value -// during mutation until the point they are stored back to their original location. -datatype $Mutation { - $Mutation(l: $Location, p: Vec int, v: T) -} - -// Representation of memory for a given type. -datatype $Memory { - $Memory(domain: [int]bool, contents: [int]T) -} - -function {:builtin "MapConst"} $ConstMemoryDomain(v: bool): [int]bool; -function {:builtin "MapConst"} $ConstMemoryContent(v: T): [int]T; -axiom $ConstMemoryDomain(false) == (lambda i: int :: false); -axiom $ConstMemoryDomain(true) == (lambda i: int :: true); - - -// Dereferences a mutation. -function {:inline} $Dereference(ref: $Mutation T): T { - ref->v -} - -// Update the value of a mutation. -function {:inline} $UpdateMutation(m: $Mutation T, v: T): $Mutation T { - $Mutation(m->l, m->p, v) -} - -function {:inline} $ChildMutation(m: $Mutation T1, offset: int, v: T2): $Mutation T2 { - $Mutation(m->l, ExtendVec(m->p, offset), v) -} - -// Return true if two mutations share the location and path -function {:inline} $IsSameMutation(parent: $Mutation T1, child: $Mutation T2 ): bool { - parent->l == child->l && parent->p == child->p -} - -// Return true if the mutation is a parent of a child which was derived with the given edge offset. This -// is used to implement write-back choices. -function {:inline} $IsParentMutation(parent: $Mutation T1, edge: int, child: $Mutation T2 ): bool { - parent->l == child->l && - (var pp := parent->p; - (var cp := child->p; - (var pl := LenVec(pp); - (var cl := LenVec(cp); - cl == pl + 1 && - (forall i: int:: i >= 0 && i < pl ==> ReadVec(pp, i) == ReadVec(cp, i)) && - $EdgeMatches(ReadVec(cp, pl), edge) - )))) -} - -// Return true if the mutation is a parent of a child, for hyper edge. -function {:inline} $IsParentMutationHyper(parent: $Mutation T1, hyper_edge: Vec int, child: $Mutation T2 ): bool { - parent->l == child->l && - (var pp := parent->p; - (var cp := child->p; - (var pl := LenVec(pp); - (var cl := LenVec(cp); - (var el := LenVec(hyper_edge); - cl == pl + el && - (forall i: int:: i >= 0 && i < pl ==> ReadVec(pp, i) == ReadVec(cp, i)) && - (forall i: int:: i >= 0 && i < el ==> $EdgeMatches(ReadVec(cp, pl + i), ReadVec(hyper_edge, i))) - ))))) -} - -function {:inline} $EdgeMatches(edge: int, edge_pattern: int): bool { - edge_pattern == -1 // wildcard - || edge_pattern == edge -} - - - -function {:inline} $SameLocation(m1: $Mutation T1, m2: $Mutation T2): bool { - m1->l == m2->l -} - -function {:inline} $HasGlobalLocation(m: $Mutation T): bool { - (m->l) is $Global -} - -function {:inline} $HasLocalLocation(m: $Mutation T, idx: int): bool { - m->l == $Local(idx) -} - -function {:inline} $GlobalLocationAddress(m: $Mutation T): int { - (m->l)->a -} - - - -// Tests whether resource exists. -function {:inline} $ResourceExists(m: $Memory T, addr: int): bool { - m->domain[addr] -} - -// Obtains Value of given resource. -function {:inline} $ResourceValue(m: $Memory T, addr: int): T { - m->contents[addr] -} - -// Update resource. -function {:inline} $ResourceUpdate(m: $Memory T, a: int, v: T): $Memory T { - $Memory(m->domain[a := true], m->contents[a := v]) -} - -// Remove resource. -function {:inline} $ResourceRemove(m: $Memory T, a: int): $Memory T { - $Memory(m->domain[a := false], m->contents) -} - -// Copies resource from memory s to m. -function {:inline} $ResourceCopy(m: $Memory T, s: $Memory T, a: int): $Memory T { - $Memory(m->domain[a := s->domain[a]], - m->contents[a := s->contents[a]]) -} - - - -// ============================================================================================ -// Abort Handling - -var $abort_flag: bool; -var $abort_code: int; - -function {:inline} $process_abort_code(code: int): int { - code -} - -const $EXEC_FAILURE_CODE: int; -axiom $EXEC_FAILURE_CODE == -1; - -// TODO(wrwg): currently we map aborts of native functions like those for vectors also to -// execution failure. This may need to be aligned with what the runtime actually does. - -procedure {:inline 1} $ExecFailureAbort() { - $abort_flag := true; - $abort_code := $EXEC_FAILURE_CODE; -} - -procedure {:inline 1} $Abort(code: int) { - $abort_flag := true; - $abort_code := code; -} - -function {:inline} $StdError(cat: int, reason: int): int { - reason * 256 + cat -} - -procedure {:inline 1} $InitVerification() { - // Set abort_flag to false, and havoc abort_code - $abort_flag := false; - havoc $abort_code; - // Initialize event store - call $InitEventStore(); -} - -// ============================================================================================ -// Instructions - - -procedure {:inline 1} $CastU8(src: int) returns (dst: int) -{ - if (src > $MAX_U8) { - call $ExecFailureAbort(); - return; - } - dst := src; -} - -procedure {:inline 1} $CastU16(src: int) returns (dst: int) -{ - if (src > $MAX_U16) { - call $ExecFailureAbort(); - return; - } - dst := src; -} - -procedure {:inline 1} $CastU32(src: int) returns (dst: int) -{ - if (src > $MAX_U32) { - call $ExecFailureAbort(); - return; - } - dst := src; -} - -procedure {:inline 1} $CastU64(src: int) returns (dst: int) -{ - if (src > $MAX_U64) { - call $ExecFailureAbort(); - return; - } - dst := src; -} - -procedure {:inline 1} $CastU128(src: int) returns (dst: int) -{ - if (src > $MAX_U128) { - call $ExecFailureAbort(); - return; - } - dst := src; -} - -procedure {:inline 1} $CastU256(src: int) returns (dst: int) -{ - if (src > $MAX_U256) { - call $ExecFailureAbort(); - return; - } - dst := src; -} - -procedure {:inline 1} $AddU8(src1: int, src2: int) returns (dst: int) -{ - if (src1 + src2 > $MAX_U8) { - call $ExecFailureAbort(); - return; - } - dst := src1 + src2; -} - -procedure {:inline 1} $AddU16(src1: int, src2: int) returns (dst: int) -{ - if (src1 + src2 > $MAX_U16) { - call $ExecFailureAbort(); - return; - } - dst := src1 + src2; -} - -procedure {:inline 1} $AddU16_unchecked(src1: int, src2: int) returns (dst: int) -{ - dst := src1 + src2; -} - -procedure {:inline 1} $AddU32(src1: int, src2: int) returns (dst: int) -{ - if (src1 + src2 > $MAX_U32) { - call $ExecFailureAbort(); - return; - } - dst := src1 + src2; -} - -procedure {:inline 1} $AddU32_unchecked(src1: int, src2: int) returns (dst: int) -{ - dst := src1 + src2; -} - -procedure {:inline 1} $AddU64(src1: int, src2: int) returns (dst: int) -{ - if (src1 + src2 > $MAX_U64) { - call $ExecFailureAbort(); - return; - } - dst := src1 + src2; -} - -procedure {:inline 1} $AddU64_unchecked(src1: int, src2: int) returns (dst: int) -{ - dst := src1 + src2; -} - -procedure {:inline 1} $AddU128(src1: int, src2: int) returns (dst: int) -{ - if (src1 + src2 > $MAX_U128) { - call $ExecFailureAbort(); - return; - } - dst := src1 + src2; -} - -procedure {:inline 1} $AddU128_unchecked(src1: int, src2: int) returns (dst: int) -{ - dst := src1 + src2; -} - -procedure {:inline 1} $AddU256(src1: int, src2: int) returns (dst: int) -{ - if (src1 + src2 > $MAX_U256) { - call $ExecFailureAbort(); - return; - } - dst := src1 + src2; -} - -procedure {:inline 1} $AddU256_unchecked(src1: int, src2: int) returns (dst: int) -{ - dst := src1 + src2; -} - -procedure {:inline 1} $Sub(src1: int, src2: int) returns (dst: int) -{ - if (src1 < src2) { - call $ExecFailureAbort(); - return; - } - dst := src1 - src2; -} - -// uninterpreted function to return an undefined value. -function $undefined_int(): int; - -// Recursive exponentiation function -// Undefined unless e >=0. $pow(0,0) is also undefined. -function $pow(n: int, e: int): int { - if n != 0 && e == 0 then 1 - else if e > 0 then n * $pow(n, e - 1) - else $undefined_int() -} - -function $shl(src1: int, p: int): int { - src1 * $pow(2, p) -} - -function $shlU8(src1: int, p: int): int { - (src1 * $pow(2, p)) mod 256 -} - -function $shlU16(src1: int, p: int): int { - (src1 * $pow(2, p)) mod 65536 -} - -function $shlU32(src1: int, p: int): int { - (src1 * $pow(2, p)) mod 4294967296 -} - -function $shlU64(src1: int, p: int): int { - (src1 * $pow(2, p)) mod 18446744073709551616 -} - -function $shlU128(src1: int, p: int): int { - (src1 * $pow(2, p)) mod 340282366920938463463374607431768211456 -} - -function $shlU256(src1: int, p: int): int { - (src1 * $pow(2, p)) mod 115792089237316195423570985008687907853269984665640564039457584007913129639936 -} - -function $shr(src1: int, p: int): int { - src1 div $pow(2, p) -} - -// We need to know the size of the destination in order to drop bits -// that have been shifted left more than that, so we have $ShlU8/16/32/64/128/256 -procedure {:inline 1} $ShlU8(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 8) { - call $ExecFailureAbort(); - return; - } - dst := $shlU8(src1, src2); -} - -// Template for cast and shift operations of bitvector types - -procedure {:inline 1} $CastBv8to8(src: bv8) returns (dst: bv8) -{ - dst := src; -} - - -function $castBv8to8(src: bv8) returns (bv8) -{ - src -} - - -function $shlBv8From8(src1: bv8, src2: bv8) returns (bv8) -{ - $Shl'Bv8'(src1, src2) -} - -procedure {:inline 1} $ShlBv8From8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if ($Ge'Bv8'(src2, 8bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv8'(src1, src2); -} - -function $shrBv8From8(src1: bv8, src2: bv8) returns (bv8) -{ - $Shr'Bv8'(src1, src2) -} - -procedure {:inline 1} $ShrBv8From8(src1: bv8, src2: bv8) returns (dst: bv8) -{ - if ($Ge'Bv8'(src2, 8bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv8'(src1, src2); -} - -procedure {:inline 1} $CastBv16to8(src: bv16) returns (dst: bv8) -{ - if ($Gt'Bv16'(src, 255bv16)) { - call $ExecFailureAbort(); - return; - } - dst := src[8:0]; -} - - - -function $shlBv8From16(src1: bv8, src2: bv16) returns (bv8) -{ - $Shl'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShlBv8From16(src1: bv8, src2: bv16) returns (dst: bv8) -{ - if ($Ge'Bv16'(src2, 8bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv8'(src1, src2[8:0]); -} - -function $shrBv8From16(src1: bv8, src2: bv16) returns (bv8) -{ - $Shr'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShrBv8From16(src1: bv8, src2: bv16) returns (dst: bv8) -{ - if ($Ge'Bv16'(src2, 8bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv8'(src1, src2[8:0]); -} - -procedure {:inline 1} $CastBv32to8(src: bv32) returns (dst: bv8) -{ - if ($Gt'Bv32'(src, 255bv32)) { - call $ExecFailureAbort(); - return; - } - dst := src[8:0]; -} - - - -function $shlBv8From32(src1: bv8, src2: bv32) returns (bv8) -{ - $Shl'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShlBv8From32(src1: bv8, src2: bv32) returns (dst: bv8) -{ - if ($Ge'Bv32'(src2, 8bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv8'(src1, src2[8:0]); -} - -function $shrBv8From32(src1: bv8, src2: bv32) returns (bv8) -{ - $Shr'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShrBv8From32(src1: bv8, src2: bv32) returns (dst: bv8) -{ - if ($Ge'Bv32'(src2, 8bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv8'(src1, src2[8:0]); -} - -procedure {:inline 1} $CastBv64to8(src: bv64) returns (dst: bv8) -{ - if ($Gt'Bv64'(src, 255bv64)) { - call $ExecFailureAbort(); - return; - } - dst := src[8:0]; -} - - -function $castBv64to8(src: bv64) returns (bv8) -{ - if ($Gt'Bv64'(src, 255bv64)) then - $Arbitrary_value_of'bv8'() - else - src[8:0] -} - - -function $shlBv8From64(src1: bv8, src2: bv64) returns (bv8) -{ - $Shl'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShlBv8From64(src1: bv8, src2: bv64) returns (dst: bv8) -{ - if ($Ge'Bv64'(src2, 8bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv8'(src1, src2[8:0]); -} - -function $shrBv8From64(src1: bv8, src2: bv64) returns (bv8) -{ - $Shr'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShrBv8From64(src1: bv8, src2: bv64) returns (dst: bv8) -{ - if ($Ge'Bv64'(src2, 8bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv8'(src1, src2[8:0]); -} - -procedure {:inline 1} $CastBv128to8(src: bv128) returns (dst: bv8) -{ - if ($Gt'Bv128'(src, 255bv128)) { - call $ExecFailureAbort(); - return; - } - dst := src[8:0]; -} - - - -function $shlBv8From128(src1: bv8, src2: bv128) returns (bv8) -{ - $Shl'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShlBv8From128(src1: bv8, src2: bv128) returns (dst: bv8) -{ - if ($Ge'Bv128'(src2, 8bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv8'(src1, src2[8:0]); -} - -function $shrBv8From128(src1: bv8, src2: bv128) returns (bv8) -{ - $Shr'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShrBv8From128(src1: bv8, src2: bv128) returns (dst: bv8) -{ - if ($Ge'Bv128'(src2, 8bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv8'(src1, src2[8:0]); -} - -procedure {:inline 1} $CastBv256to8(src: bv256) returns (dst: bv8) -{ - if ($Gt'Bv256'(src, 255bv256)) { - call $ExecFailureAbort(); - return; - } - dst := src[8:0]; -} - - -function $castBv256to8(src: bv256) returns (bv8) -{ - if ($Gt'Bv256'(src, 255bv256)) then - $Arbitrary_value_of'bv8'() - else - src[8:0] -} - - -function $shlBv8From256(src1: bv8, src2: bv256) returns (bv8) -{ - $Shl'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShlBv8From256(src1: bv8, src2: bv256) returns (dst: bv8) -{ - if ($Ge'Bv256'(src2, 8bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv8'(src1, src2[8:0]); -} - -function $shrBv8From256(src1: bv8, src2: bv256) returns (bv8) -{ - $Shr'Bv8'(src1, src2[8:0]) -} - -procedure {:inline 1} $ShrBv8From256(src1: bv8, src2: bv256) returns (dst: bv8) -{ - if ($Ge'Bv256'(src2, 8bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv8'(src1, src2[8:0]); -} - -procedure {:inline 1} $CastBv8to16(src: bv8) returns (dst: bv16) -{ - dst := 0bv8 ++ src; -} - - - -function $shlBv16From8(src1: bv16, src2: bv8) returns (bv16) -{ - $Shl'Bv16'(src1, 0bv8 ++ src2) -} - -procedure {:inline 1} $ShlBv16From8(src1: bv16, src2: bv8) returns (dst: bv16) -{ - if ($Ge'Bv8'(src2, 16bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv16'(src1, 0bv8 ++ src2); -} - -function $shrBv16From8(src1: bv16, src2: bv8) returns (bv16) -{ - $Shr'Bv16'(src1, 0bv8 ++ src2) -} - -procedure {:inline 1} $ShrBv16From8(src1: bv16, src2: bv8) returns (dst: bv16) -{ - if ($Ge'Bv8'(src2, 16bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv16'(src1, 0bv8 ++ src2); -} - -procedure {:inline 1} $CastBv16to16(src: bv16) returns (dst: bv16) -{ - dst := src; -} - - - -function $shlBv16From16(src1: bv16, src2: bv16) returns (bv16) -{ - $Shl'Bv16'(src1, src2) -} - -procedure {:inline 1} $ShlBv16From16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if ($Ge'Bv16'(src2, 16bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv16'(src1, src2); -} - -function $shrBv16From16(src1: bv16, src2: bv16) returns (bv16) -{ - $Shr'Bv16'(src1, src2) -} - -procedure {:inline 1} $ShrBv16From16(src1: bv16, src2: bv16) returns (dst: bv16) -{ - if ($Ge'Bv16'(src2, 16bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv16'(src1, src2); -} - -procedure {:inline 1} $CastBv32to16(src: bv32) returns (dst: bv16) -{ - if ($Gt'Bv32'(src, 65535bv32)) { - call $ExecFailureAbort(); - return; - } - dst := src[16:0]; -} - - - -function $shlBv16From32(src1: bv16, src2: bv32) returns (bv16) -{ - $Shl'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShlBv16From32(src1: bv16, src2: bv32) returns (dst: bv16) -{ - if ($Ge'Bv32'(src2, 16bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv16'(src1, src2[16:0]); -} - -function $shrBv16From32(src1: bv16, src2: bv32) returns (bv16) -{ - $Shr'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShrBv16From32(src1: bv16, src2: bv32) returns (dst: bv16) -{ - if ($Ge'Bv32'(src2, 16bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv16'(src1, src2[16:0]); -} - -procedure {:inline 1} $CastBv64to16(src: bv64) returns (dst: bv16) -{ - if ($Gt'Bv64'(src, 65535bv64)) { - call $ExecFailureAbort(); - return; - } - dst := src[16:0]; -} - - - -function $shlBv16From64(src1: bv16, src2: bv64) returns (bv16) -{ - $Shl'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShlBv16From64(src1: bv16, src2: bv64) returns (dst: bv16) -{ - if ($Ge'Bv64'(src2, 16bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv16'(src1, src2[16:0]); -} - -function $shrBv16From64(src1: bv16, src2: bv64) returns (bv16) -{ - $Shr'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShrBv16From64(src1: bv16, src2: bv64) returns (dst: bv16) -{ - if ($Ge'Bv64'(src2, 16bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv16'(src1, src2[16:0]); -} - -procedure {:inline 1} $CastBv128to16(src: bv128) returns (dst: bv16) -{ - if ($Gt'Bv128'(src, 65535bv128)) { - call $ExecFailureAbort(); - return; - } - dst := src[16:0]; -} - - - -function $shlBv16From128(src1: bv16, src2: bv128) returns (bv16) -{ - $Shl'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShlBv16From128(src1: bv16, src2: bv128) returns (dst: bv16) -{ - if ($Ge'Bv128'(src2, 16bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv16'(src1, src2[16:0]); -} - -function $shrBv16From128(src1: bv16, src2: bv128) returns (bv16) -{ - $Shr'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShrBv16From128(src1: bv16, src2: bv128) returns (dst: bv16) -{ - if ($Ge'Bv128'(src2, 16bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv16'(src1, src2[16:0]); -} - -procedure {:inline 1} $CastBv256to16(src: bv256) returns (dst: bv16) -{ - if ($Gt'Bv256'(src, 65535bv256)) { - call $ExecFailureAbort(); - return; - } - dst := src[16:0]; -} - - - -function $shlBv16From256(src1: bv16, src2: bv256) returns (bv16) -{ - $Shl'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShlBv16From256(src1: bv16, src2: bv256) returns (dst: bv16) -{ - if ($Ge'Bv256'(src2, 16bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv16'(src1, src2[16:0]); -} - -function $shrBv16From256(src1: bv16, src2: bv256) returns (bv16) -{ - $Shr'Bv16'(src1, src2[16:0]) -} - -procedure {:inline 1} $ShrBv16From256(src1: bv16, src2: bv256) returns (dst: bv16) -{ - if ($Ge'Bv256'(src2, 16bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv16'(src1, src2[16:0]); -} - -procedure {:inline 1} $CastBv8to32(src: bv8) returns (dst: bv32) -{ - dst := 0bv24 ++ src; -} - - - -function $shlBv32From8(src1: bv32, src2: bv8) returns (bv32) -{ - $Shl'Bv32'(src1, 0bv24 ++ src2) -} - -procedure {:inline 1} $ShlBv32From8(src1: bv32, src2: bv8) returns (dst: bv32) -{ - if ($Ge'Bv8'(src2, 32bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv32'(src1, 0bv24 ++ src2); -} - -function $shrBv32From8(src1: bv32, src2: bv8) returns (bv32) -{ - $Shr'Bv32'(src1, 0bv24 ++ src2) -} - -procedure {:inline 1} $ShrBv32From8(src1: bv32, src2: bv8) returns (dst: bv32) -{ - if ($Ge'Bv8'(src2, 32bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv32'(src1, 0bv24 ++ src2); -} - -procedure {:inline 1} $CastBv16to32(src: bv16) returns (dst: bv32) -{ - dst := 0bv16 ++ src; -} - - - -function $shlBv32From16(src1: bv32, src2: bv16) returns (bv32) -{ - $Shl'Bv32'(src1, 0bv16 ++ src2) -} - -procedure {:inline 1} $ShlBv32From16(src1: bv32, src2: bv16) returns (dst: bv32) -{ - if ($Ge'Bv16'(src2, 32bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv32'(src1, 0bv16 ++ src2); -} - -function $shrBv32From16(src1: bv32, src2: bv16) returns (bv32) -{ - $Shr'Bv32'(src1, 0bv16 ++ src2) -} - -procedure {:inline 1} $ShrBv32From16(src1: bv32, src2: bv16) returns (dst: bv32) -{ - if ($Ge'Bv16'(src2, 32bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv32'(src1, 0bv16 ++ src2); -} - -procedure {:inline 1} $CastBv32to32(src: bv32) returns (dst: bv32) -{ - dst := src; -} - - - -function $shlBv32From32(src1: bv32, src2: bv32) returns (bv32) -{ - $Shl'Bv32'(src1, src2) -} - -procedure {:inline 1} $ShlBv32From32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if ($Ge'Bv32'(src2, 32bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv32'(src1, src2); -} - -function $shrBv32From32(src1: bv32, src2: bv32) returns (bv32) -{ - $Shr'Bv32'(src1, src2) -} - -procedure {:inline 1} $ShrBv32From32(src1: bv32, src2: bv32) returns (dst: bv32) -{ - if ($Ge'Bv32'(src2, 32bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv32'(src1, src2); -} - -procedure {:inline 1} $CastBv64to32(src: bv64) returns (dst: bv32) -{ - if ($Gt'Bv64'(src, 2147483647bv64)) { - call $ExecFailureAbort(); - return; - } - dst := src[32:0]; -} - - - -function $shlBv32From64(src1: bv32, src2: bv64) returns (bv32) -{ - $Shl'Bv32'(src1, src2[32:0]) -} - -procedure {:inline 1} $ShlBv32From64(src1: bv32, src2: bv64) returns (dst: bv32) -{ - if ($Ge'Bv64'(src2, 32bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv32'(src1, src2[32:0]); -} - -function $shrBv32From64(src1: bv32, src2: bv64) returns (bv32) -{ - $Shr'Bv32'(src1, src2[32:0]) -} - -procedure {:inline 1} $ShrBv32From64(src1: bv32, src2: bv64) returns (dst: bv32) -{ - if ($Ge'Bv64'(src2, 32bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv32'(src1, src2[32:0]); -} - -procedure {:inline 1} $CastBv128to32(src: bv128) returns (dst: bv32) -{ - if ($Gt'Bv128'(src, 2147483647bv128)) { - call $ExecFailureAbort(); - return; - } - dst := src[32:0]; -} - - - -function $shlBv32From128(src1: bv32, src2: bv128) returns (bv32) -{ - $Shl'Bv32'(src1, src2[32:0]) -} - -procedure {:inline 1} $ShlBv32From128(src1: bv32, src2: bv128) returns (dst: bv32) -{ - if ($Ge'Bv128'(src2, 32bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv32'(src1, src2[32:0]); -} - -function $shrBv32From128(src1: bv32, src2: bv128) returns (bv32) -{ - $Shr'Bv32'(src1, src2[32:0]) -} - -procedure {:inline 1} $ShrBv32From128(src1: bv32, src2: bv128) returns (dst: bv32) -{ - if ($Ge'Bv128'(src2, 32bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv32'(src1, src2[32:0]); -} - -procedure {:inline 1} $CastBv256to32(src: bv256) returns (dst: bv32) -{ - if ($Gt'Bv256'(src, 2147483647bv256)) { - call $ExecFailureAbort(); - return; - } - dst := src[32:0]; -} - - - -function $shlBv32From256(src1: bv32, src2: bv256) returns (bv32) -{ - $Shl'Bv32'(src1, src2[32:0]) -} - -procedure {:inline 1} $ShlBv32From256(src1: bv32, src2: bv256) returns (dst: bv32) -{ - if ($Ge'Bv256'(src2, 32bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv32'(src1, src2[32:0]); -} - -function $shrBv32From256(src1: bv32, src2: bv256) returns (bv32) -{ - $Shr'Bv32'(src1, src2[32:0]) -} - -procedure {:inline 1} $ShrBv32From256(src1: bv32, src2: bv256) returns (dst: bv32) -{ - if ($Ge'Bv256'(src2, 32bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv32'(src1, src2[32:0]); -} - -procedure {:inline 1} $CastBv8to64(src: bv8) returns (dst: bv64) -{ - dst := 0bv56 ++ src; -} - - -function $castBv8to64(src: bv8) returns (bv64) -{ - 0bv56 ++ src -} - - -function $shlBv64From8(src1: bv64, src2: bv8) returns (bv64) -{ - $Shl'Bv64'(src1, 0bv56 ++ src2) -} - -procedure {:inline 1} $ShlBv64From8(src1: bv64, src2: bv8) returns (dst: bv64) -{ - if ($Ge'Bv8'(src2, 64bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv64'(src1, 0bv56 ++ src2); -} - -function $shrBv64From8(src1: bv64, src2: bv8) returns (bv64) -{ - $Shr'Bv64'(src1, 0bv56 ++ src2) -} - -procedure {:inline 1} $ShrBv64From8(src1: bv64, src2: bv8) returns (dst: bv64) -{ - if ($Ge'Bv8'(src2, 64bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv64'(src1, 0bv56 ++ src2); -} - -procedure {:inline 1} $CastBv16to64(src: bv16) returns (dst: bv64) -{ - dst := 0bv48 ++ src; -} - - - -function $shlBv64From16(src1: bv64, src2: bv16) returns (bv64) -{ - $Shl'Bv64'(src1, 0bv48 ++ src2) -} - -procedure {:inline 1} $ShlBv64From16(src1: bv64, src2: bv16) returns (dst: bv64) -{ - if ($Ge'Bv16'(src2, 64bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv64'(src1, 0bv48 ++ src2); -} - -function $shrBv64From16(src1: bv64, src2: bv16) returns (bv64) -{ - $Shr'Bv64'(src1, 0bv48 ++ src2) -} - -procedure {:inline 1} $ShrBv64From16(src1: bv64, src2: bv16) returns (dst: bv64) -{ - if ($Ge'Bv16'(src2, 64bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv64'(src1, 0bv48 ++ src2); -} - -procedure {:inline 1} $CastBv32to64(src: bv32) returns (dst: bv64) -{ - dst := 0bv32 ++ src; -} - - - -function $shlBv64From32(src1: bv64, src2: bv32) returns (bv64) -{ - $Shl'Bv64'(src1, 0bv32 ++ src2) -} - -procedure {:inline 1} $ShlBv64From32(src1: bv64, src2: bv32) returns (dst: bv64) -{ - if ($Ge'Bv32'(src2, 64bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv64'(src1, 0bv32 ++ src2); -} - -function $shrBv64From32(src1: bv64, src2: bv32) returns (bv64) -{ - $Shr'Bv64'(src1, 0bv32 ++ src2) -} - -procedure {:inline 1} $ShrBv64From32(src1: bv64, src2: bv32) returns (dst: bv64) -{ - if ($Ge'Bv32'(src2, 64bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv64'(src1, 0bv32 ++ src2); -} - -procedure {:inline 1} $CastBv64to64(src: bv64) returns (dst: bv64) -{ - dst := src; -} - - -function $castBv64to64(src: bv64) returns (bv64) -{ - src -} - - -function $shlBv64From64(src1: bv64, src2: bv64) returns (bv64) -{ - $Shl'Bv64'(src1, src2) -} - -procedure {:inline 1} $ShlBv64From64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if ($Ge'Bv64'(src2, 64bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv64'(src1, src2); -} - -function $shrBv64From64(src1: bv64, src2: bv64) returns (bv64) -{ - $Shr'Bv64'(src1, src2) -} - -procedure {:inline 1} $ShrBv64From64(src1: bv64, src2: bv64) returns (dst: bv64) -{ - if ($Ge'Bv64'(src2, 64bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv64'(src1, src2); -} - -procedure {:inline 1} $CastBv128to64(src: bv128) returns (dst: bv64) -{ - if ($Gt'Bv128'(src, 18446744073709551615bv128)) { - call $ExecFailureAbort(); - return; - } - dst := src[64:0]; -} - - - -function $shlBv64From128(src1: bv64, src2: bv128) returns (bv64) -{ - $Shl'Bv64'(src1, src2[64:0]) -} - -procedure {:inline 1} $ShlBv64From128(src1: bv64, src2: bv128) returns (dst: bv64) -{ - if ($Ge'Bv128'(src2, 64bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv64'(src1, src2[64:0]); -} - -function $shrBv64From128(src1: bv64, src2: bv128) returns (bv64) -{ - $Shr'Bv64'(src1, src2[64:0]) -} - -procedure {:inline 1} $ShrBv64From128(src1: bv64, src2: bv128) returns (dst: bv64) -{ - if ($Ge'Bv128'(src2, 64bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv64'(src1, src2[64:0]); -} - -procedure {:inline 1} $CastBv256to64(src: bv256) returns (dst: bv64) -{ - if ($Gt'Bv256'(src, 18446744073709551615bv256)) { - call $ExecFailureAbort(); - return; - } - dst := src[64:0]; -} - - -function $castBv256to64(src: bv256) returns (bv64) -{ - if ($Gt'Bv256'(src, 18446744073709551615bv256)) then - $Arbitrary_value_of'bv64'() - else - src[64:0] -} - - -function $shlBv64From256(src1: bv64, src2: bv256) returns (bv64) -{ - $Shl'Bv64'(src1, src2[64:0]) -} - -procedure {:inline 1} $ShlBv64From256(src1: bv64, src2: bv256) returns (dst: bv64) -{ - if ($Ge'Bv256'(src2, 64bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv64'(src1, src2[64:0]); -} - -function $shrBv64From256(src1: bv64, src2: bv256) returns (bv64) -{ - $Shr'Bv64'(src1, src2[64:0]) -} - -procedure {:inline 1} $ShrBv64From256(src1: bv64, src2: bv256) returns (dst: bv64) -{ - if ($Ge'Bv256'(src2, 64bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv64'(src1, src2[64:0]); -} - -procedure {:inline 1} $CastBv8to128(src: bv8) returns (dst: bv128) -{ - dst := 0bv120 ++ src; -} - - - -function $shlBv128From8(src1: bv128, src2: bv8) returns (bv128) -{ - $Shl'Bv128'(src1, 0bv120 ++ src2) -} - -procedure {:inline 1} $ShlBv128From8(src1: bv128, src2: bv8) returns (dst: bv128) -{ - if ($Ge'Bv8'(src2, 128bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv128'(src1, 0bv120 ++ src2); -} - -function $shrBv128From8(src1: bv128, src2: bv8) returns (bv128) -{ - $Shr'Bv128'(src1, 0bv120 ++ src2) -} - -procedure {:inline 1} $ShrBv128From8(src1: bv128, src2: bv8) returns (dst: bv128) -{ - if ($Ge'Bv8'(src2, 128bv8)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv128'(src1, 0bv120 ++ src2); -} - -procedure {:inline 1} $CastBv16to128(src: bv16) returns (dst: bv128) -{ - dst := 0bv112 ++ src; -} - - - -function $shlBv128From16(src1: bv128, src2: bv16) returns (bv128) -{ - $Shl'Bv128'(src1, 0bv112 ++ src2) -} - -procedure {:inline 1} $ShlBv128From16(src1: bv128, src2: bv16) returns (dst: bv128) -{ - if ($Ge'Bv16'(src2, 128bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv128'(src1, 0bv112 ++ src2); -} - -function $shrBv128From16(src1: bv128, src2: bv16) returns (bv128) -{ - $Shr'Bv128'(src1, 0bv112 ++ src2) -} - -procedure {:inline 1} $ShrBv128From16(src1: bv128, src2: bv16) returns (dst: bv128) -{ - if ($Ge'Bv16'(src2, 128bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv128'(src1, 0bv112 ++ src2); -} - -procedure {:inline 1} $CastBv32to128(src: bv32) returns (dst: bv128) -{ - dst := 0bv96 ++ src; -} - - - -function $shlBv128From32(src1: bv128, src2: bv32) returns (bv128) -{ - $Shl'Bv128'(src1, 0bv96 ++ src2) -} - -procedure {:inline 1} $ShlBv128From32(src1: bv128, src2: bv32) returns (dst: bv128) -{ - if ($Ge'Bv32'(src2, 128bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv128'(src1, 0bv96 ++ src2); -} - -function $shrBv128From32(src1: bv128, src2: bv32) returns (bv128) -{ - $Shr'Bv128'(src1, 0bv96 ++ src2) -} - -procedure {:inline 1} $ShrBv128From32(src1: bv128, src2: bv32) returns (dst: bv128) -{ - if ($Ge'Bv32'(src2, 128bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv128'(src1, 0bv96 ++ src2); -} - -procedure {:inline 1} $CastBv64to128(src: bv64) returns (dst: bv128) -{ - dst := 0bv64 ++ src; -} - - - -function $shlBv128From64(src1: bv128, src2: bv64) returns (bv128) -{ - $Shl'Bv128'(src1, 0bv64 ++ src2) -} - -procedure {:inline 1} $ShlBv128From64(src1: bv128, src2: bv64) returns (dst: bv128) -{ - if ($Ge'Bv64'(src2, 128bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv128'(src1, 0bv64 ++ src2); -} - -function $shrBv128From64(src1: bv128, src2: bv64) returns (bv128) -{ - $Shr'Bv128'(src1, 0bv64 ++ src2) -} - -procedure {:inline 1} $ShrBv128From64(src1: bv128, src2: bv64) returns (dst: bv128) -{ - if ($Ge'Bv64'(src2, 128bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv128'(src1, 0bv64 ++ src2); -} - -procedure {:inline 1} $CastBv128to128(src: bv128) returns (dst: bv128) -{ - dst := src; -} - - - -function $shlBv128From128(src1: bv128, src2: bv128) returns (bv128) -{ - $Shl'Bv128'(src1, src2) -} - -procedure {:inline 1} $ShlBv128From128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if ($Ge'Bv128'(src2, 128bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv128'(src1, src2); -} - -function $shrBv128From128(src1: bv128, src2: bv128) returns (bv128) -{ - $Shr'Bv128'(src1, src2) -} - -procedure {:inline 1} $ShrBv128From128(src1: bv128, src2: bv128) returns (dst: bv128) -{ - if ($Ge'Bv128'(src2, 128bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv128'(src1, src2); -} - -procedure {:inline 1} $CastBv256to128(src: bv256) returns (dst: bv128) -{ - if ($Gt'Bv256'(src, 340282366920938463463374607431768211455bv256)) { - call $ExecFailureAbort(); - return; - } - dst := src[128:0]; -} - - - -function $shlBv128From256(src1: bv128, src2: bv256) returns (bv128) -{ - $Shl'Bv128'(src1, src2[128:0]) -} - -procedure {:inline 1} $ShlBv128From256(src1: bv128, src2: bv256) returns (dst: bv128) -{ - if ($Ge'Bv256'(src2, 128bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv128'(src1, src2[128:0]); -} - -function $shrBv128From256(src1: bv128, src2: bv256) returns (bv128) -{ - $Shr'Bv128'(src1, src2[128:0]) -} - -procedure {:inline 1} $ShrBv128From256(src1: bv128, src2: bv256) returns (dst: bv128) -{ - if ($Ge'Bv256'(src2, 128bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv128'(src1, src2[128:0]); -} - -procedure {:inline 1} $CastBv8to256(src: bv8) returns (dst: bv256) -{ - dst := 0bv248 ++ src; -} - - -function $castBv8to256(src: bv8) returns (bv256) -{ - 0bv248 ++ src -} - - -function $shlBv256From8(src1: bv256, src2: bv8) returns (bv256) -{ - $Shl'Bv256'(src1, 0bv248 ++ src2) -} - -procedure {:inline 1} $ShlBv256From8(src1: bv256, src2: bv8) returns (dst: bv256) -{ - assume $bv2int.8(src2) >= 0 && $bv2int.8(src2) < 256; - dst := $Shl'Bv256'(src1, 0bv248 ++ src2); -} - -function $shrBv256From8(src1: bv256, src2: bv8) returns (bv256) -{ - $Shr'Bv256'(src1, 0bv248 ++ src2) -} - -procedure {:inline 1} $ShrBv256From8(src1: bv256, src2: bv8) returns (dst: bv256) -{ - assume $bv2int.8(src2) >= 0 && $bv2int.8(src2) < 256; - dst := $Shr'Bv256'(src1, 0bv248 ++ src2); -} - -procedure {:inline 1} $CastBv16to256(src: bv16) returns (dst: bv256) -{ - dst := 0bv240 ++ src; -} - - - -function $shlBv256From16(src1: bv256, src2: bv16) returns (bv256) -{ - $Shl'Bv256'(src1, 0bv240 ++ src2) -} - -procedure {:inline 1} $ShlBv256From16(src1: bv256, src2: bv16) returns (dst: bv256) -{ - if ($Ge'Bv16'(src2, 256bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv256'(src1, 0bv240 ++ src2); -} - -function $shrBv256From16(src1: bv256, src2: bv16) returns (bv256) -{ - $Shr'Bv256'(src1, 0bv240 ++ src2) -} - -procedure {:inline 1} $ShrBv256From16(src1: bv256, src2: bv16) returns (dst: bv256) -{ - if ($Ge'Bv16'(src2, 256bv16)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv256'(src1, 0bv240 ++ src2); -} - -procedure {:inline 1} $CastBv32to256(src: bv32) returns (dst: bv256) -{ - dst := 0bv224 ++ src; -} - - - -function $shlBv256From32(src1: bv256, src2: bv32) returns (bv256) -{ - $Shl'Bv256'(src1, 0bv224 ++ src2) -} - -procedure {:inline 1} $ShlBv256From32(src1: bv256, src2: bv32) returns (dst: bv256) -{ - if ($Ge'Bv32'(src2, 256bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv256'(src1, 0bv224 ++ src2); -} - -function $shrBv256From32(src1: bv256, src2: bv32) returns (bv256) -{ - $Shr'Bv256'(src1, 0bv224 ++ src2) -} - -procedure {:inline 1} $ShrBv256From32(src1: bv256, src2: bv32) returns (dst: bv256) -{ - if ($Ge'Bv32'(src2, 256bv32)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv256'(src1, 0bv224 ++ src2); -} - -procedure {:inline 1} $CastBv64to256(src: bv64) returns (dst: bv256) -{ - dst := 0bv192 ++ src; -} - - -function $castBv64to256(src: bv64) returns (bv256) -{ - 0bv192 ++ src -} - - -function $shlBv256From64(src1: bv256, src2: bv64) returns (bv256) -{ - $Shl'Bv256'(src1, 0bv192 ++ src2) -} - -procedure {:inline 1} $ShlBv256From64(src1: bv256, src2: bv64) returns (dst: bv256) -{ - if ($Ge'Bv64'(src2, 256bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv256'(src1, 0bv192 ++ src2); -} - -function $shrBv256From64(src1: bv256, src2: bv64) returns (bv256) -{ - $Shr'Bv256'(src1, 0bv192 ++ src2) -} - -procedure {:inline 1} $ShrBv256From64(src1: bv256, src2: bv64) returns (dst: bv256) -{ - if ($Ge'Bv64'(src2, 256bv64)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv256'(src1, 0bv192 ++ src2); -} - -procedure {:inline 1} $CastBv128to256(src: bv128) returns (dst: bv256) -{ - dst := 0bv128 ++ src; -} - - - -function $shlBv256From128(src1: bv256, src2: bv128) returns (bv256) -{ - $Shl'Bv256'(src1, 0bv128 ++ src2) -} - -procedure {:inline 1} $ShlBv256From128(src1: bv256, src2: bv128) returns (dst: bv256) -{ - if ($Ge'Bv128'(src2, 256bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv256'(src1, 0bv128 ++ src2); -} - -function $shrBv256From128(src1: bv256, src2: bv128) returns (bv256) -{ - $Shr'Bv256'(src1, 0bv128 ++ src2) -} - -procedure {:inline 1} $ShrBv256From128(src1: bv256, src2: bv128) returns (dst: bv256) -{ - if ($Ge'Bv128'(src2, 256bv128)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv256'(src1, 0bv128 ++ src2); -} - -procedure {:inline 1} $CastBv256to256(src: bv256) returns (dst: bv256) -{ - dst := src; -} - - -function $castBv256to256(src: bv256) returns (bv256) -{ - src -} - - -function $shlBv256From256(src1: bv256, src2: bv256) returns (bv256) -{ - $Shl'Bv256'(src1, src2) -} - -procedure {:inline 1} $ShlBv256From256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if ($Ge'Bv256'(src2, 256bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shl'Bv256'(src1, src2); -} - -function $shrBv256From256(src1: bv256, src2: bv256) returns (bv256) -{ - $Shr'Bv256'(src1, src2) -} - -procedure {:inline 1} $ShrBv256From256(src1: bv256, src2: bv256) returns (dst: bv256) -{ - if ($Ge'Bv256'(src2, 256bv256)) { - call $ExecFailureAbort(); - return; - } - - dst := $Shr'Bv256'(src1, src2); -} - -procedure {:inline 1} $ShlU16(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 16) { - call $ExecFailureAbort(); - return; - } - dst := $shlU16(src1, src2); -} - -procedure {:inline 1} $ShlU32(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 32) { - call $ExecFailureAbort(); - return; - } - dst := $shlU32(src1, src2); -} - -procedure {:inline 1} $ShlU64(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 64) { - call $ExecFailureAbort(); - return; - } - dst := $shlU64(src1, src2); -} - -procedure {:inline 1} $ShlU128(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 128) { - call $ExecFailureAbort(); - return; - } - dst := $shlU128(src1, src2); -} - -procedure {:inline 1} $ShlU256(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - dst := $shlU256(src1, src2); -} - -procedure {:inline 1} $Shr(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - dst := $shr(src1, src2); -} - -procedure {:inline 1} $ShrU8(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 8) { - call $ExecFailureAbort(); - return; - } - dst := $shr(src1, src2); -} - -procedure {:inline 1} $ShrU16(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 16) { - call $ExecFailureAbort(); - return; - } - dst := $shr(src1, src2); -} - -procedure {:inline 1} $ShrU32(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 32) { - call $ExecFailureAbort(); - return; - } - dst := $shr(src1, src2); -} - -procedure {:inline 1} $ShrU64(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 64) { - call $ExecFailureAbort(); - return; - } - dst := $shr(src1, src2); -} - -procedure {:inline 1} $ShrU128(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - if (src2 >= 128) { - call $ExecFailureAbort(); - return; - } - dst := $shr(src1, src2); -} - -procedure {:inline 1} $ShrU256(src1: int, src2: int) returns (dst: int) -{ - var res: int; - // src2 is a u8 - assume src2 >= 0 && src2 < 256; - dst := $shr(src1, src2); -} - -procedure {:inline 1} $MulU8(src1: int, src2: int) returns (dst: int) -{ - if (src1 * src2 > $MAX_U8) { - call $ExecFailureAbort(); - return; - } - dst := src1 * src2; -} - -procedure {:inline 1} $MulU16(src1: int, src2: int) returns (dst: int) -{ - if (src1 * src2 > $MAX_U16) { - call $ExecFailureAbort(); - return; - } - dst := src1 * src2; -} - -procedure {:inline 1} $MulU32(src1: int, src2: int) returns (dst: int) -{ - if (src1 * src2 > $MAX_U32) { - call $ExecFailureAbort(); - return; - } - dst := src1 * src2; -} - -procedure {:inline 1} $MulU64(src1: int, src2: int) returns (dst: int) -{ - if (src1 * src2 > $MAX_U64) { - call $ExecFailureAbort(); - return; - } - dst := src1 * src2; -} - -procedure {:inline 1} $MulU128(src1: int, src2: int) returns (dst: int) -{ - if (src1 * src2 > $MAX_U128) { - call $ExecFailureAbort(); - return; - } - dst := src1 * src2; -} - -procedure {:inline 1} $MulU256(src1: int, src2: int) returns (dst: int) -{ - if (src1 * src2 > $MAX_U256) { - call $ExecFailureAbort(); - return; - } - dst := src1 * src2; -} - -procedure {:inline 1} $Div(src1: int, src2: int) returns (dst: int) -{ - if (src2 == 0) { - call $ExecFailureAbort(); - return; - } - dst := src1 div src2; -} - -procedure {:inline 1} $Mod(src1: int, src2: int) returns (dst: int) -{ - if (src2 == 0) { - call $ExecFailureAbort(); - return; - } - dst := src1 mod src2; -} - -procedure {:inline 1} $ArithBinaryUnimplemented(src1: int, src2: int) returns (dst: int); - -procedure {:inline 1} $Lt(src1: int, src2: int) returns (dst: bool) -{ - dst := src1 < src2; -} - -procedure {:inline 1} $Gt(src1: int, src2: int) returns (dst: bool) -{ - dst := src1 > src2; -} - -procedure {:inline 1} $Le(src1: int, src2: int) returns (dst: bool) -{ - dst := src1 <= src2; -} - -procedure {:inline 1} $Ge(src1: int, src2: int) returns (dst: bool) -{ - dst := src1 >= src2; -} - -procedure {:inline 1} $And(src1: bool, src2: bool) returns (dst: bool) -{ - dst := src1 && src2; -} - -procedure {:inline 1} $Or(src1: bool, src2: bool) returns (dst: bool) -{ - dst := src1 || src2; -} - -procedure {:inline 1} $Not(src: bool) returns (dst: bool) -{ - dst := !src; -} - -// Pack and Unpack are auto-generated for each type T - - -// ================================================================================== -// Native Vector - -function {:inline} $SliceVecByRange(v: Vec T, r: $Range): Vec T { - SliceVec(v, r->lb, r->ub) -} - -// ---------------------------------------------------------------------------------- -// Native Vector implementation for element type `#0` - -// Not inlined. It appears faster this way. -function $IsEqual'vec'#0''(v1: Vec (#0), v2: Vec (#0)): bool { - LenVec(v1) == LenVec(v2) && - (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'#0'(ReadVec(v1, i), ReadVec(v2, i))) -} - -// Not inlined. -function $IsPrefix'vec'#0''(v: Vec (#0), prefix: Vec (#0)): bool { - LenVec(v) >= LenVec(prefix) && - (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'#0'(ReadVec(v, i), ReadVec(prefix, i))) -} - -// Not inlined. -function $IsSuffix'vec'#0''(v: Vec (#0), suffix: Vec (#0)): bool { - LenVec(v) >= LenVec(suffix) && - (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'#0'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) -} - -// Not inlined. -function $IsValid'vec'#0''(v: Vec (#0)): bool { - $IsValid'u64'(LenVec(v)) && - (forall i: int:: InRangeVec(v, i) ==> $IsValid'#0'(ReadVec(v, i))) -} - - -function {:inline} $ContainsVec'#0'(v: Vec (#0), e: #0): bool { - (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'#0'(ReadVec(v, i), e)) -} - -function $IndexOfVec'#0'(v: Vec (#0), e: #0): int; -axiom (forall v: Vec (#0), e: #0:: {$IndexOfVec'#0'(v, e)} - (var i := $IndexOfVec'#0'(v, e); - if (!$ContainsVec'#0'(v, e)) then i == -1 - else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'#0'(ReadVec(v, i), e) && - (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'#0'(ReadVec(v, j), e)))); - - -function {:inline} $RangeVec'#0'(v: Vec (#0)): $Range { - $Range(0, LenVec(v)) -} - - -function {:inline} $EmptyVec'#0'(): Vec (#0) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_empty'#0'() returns (v: Vec (#0)) { - v := EmptyVec(); -} - -function {:inline} $1_vector_$empty'#0'(): Vec (#0) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_is_empty'#0'(v: Vec (#0)) returns (b: bool) { - b := IsEmptyVec(v); -} - -procedure {:inline 1} $1_vector_push_back'#0'(m: $Mutation (Vec (#0)), val: #0) returns (m': $Mutation (Vec (#0))) { - m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); -} - -function {:inline} $1_vector_$push_back'#0'(v: Vec (#0), val: #0): Vec (#0) { - ExtendVec(v, val) -} - -procedure {:inline 1} $1_vector_pop_back'#0'(m: $Mutation (Vec (#0))) returns (e: #0, m': $Mutation (Vec (#0))) { - var v: Vec (#0); - var len: int; - v := $Dereference(m); - len := LenVec(v); - if (len == 0) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, len-1); - m' := $UpdateMutation(m, RemoveVec(v)); -} - -procedure {:inline 1} $1_vector_append'#0'(m: $Mutation (Vec (#0)), other: Vec (#0)) returns (m': $Mutation (Vec (#0))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); -} - -procedure {:inline 1} $1_vector_reverse'#0'(m: $Mutation (Vec (#0))) returns (m': $Mutation (Vec (#0))) { - m' := $UpdateMutation(m, ReverseVec($Dereference(m))); -} - -procedure {:inline 1} $1_vector_reverse_append'#0'(m: $Mutation (Vec (#0)), other: Vec (#0)) returns (m': $Mutation (Vec (#0))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); -} - -procedure {:inline 1} $1_vector_trim_reverse'#0'(m: $Mutation (Vec (#0)), new_len: int) returns (v: (Vec (#0)), m': $Mutation (Vec (#0))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - v := ReverseVec(v); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_trim'#0'(m: $Mutation (Vec (#0)), new_len: int) returns (v: (Vec (#0)), m': $Mutation (Vec (#0))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_reverse_slice'#0'(m: $Mutation (Vec (#0)), left: int, right: int) returns (m': $Mutation (Vec (#0))) { - var left_vec: Vec (#0); - var mid_vec: Vec (#0); - var right_vec: Vec (#0); - var v: Vec (#0); - if (left > right) { - call $ExecFailureAbort(); - return; - } - if (left == right) { - m' := m; - return; - } - v := $Dereference(m); - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_vec := ReverseVec(SliceVec(v, left, right)); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); -} - -procedure {:inline 1} $1_vector_rotate'#0'(m: $Mutation (Vec (#0)), rot: int) returns (n: int, m': $Mutation (Vec (#0))) { - var v: Vec (#0); - var len: int; - var left_vec: Vec (#0); - var right_vec: Vec (#0); - v := $Dereference(m); - if (!(rot >= 0 && rot <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, rot); - right_vec := SliceVec(v, rot, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); - n := LenVec(v) - rot; -} - -procedure {:inline 1} $1_vector_rotate_slice'#0'(m: $Mutation (Vec (#0)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (#0))) { - var left_vec: Vec (#0); - var mid_vec: Vec (#0); - var right_vec: Vec (#0); - var mid_left_vec: Vec (#0); - var mid_right_vec: Vec (#0); - var v: Vec (#0); - v := $Dereference(m); - if (!(left <= rot && rot <= right)) { - call $ExecFailureAbort(); - return; - } - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - v := $Dereference(m); - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_left_vec := SliceVec(v, left, rot); - mid_right_vec := SliceVec(v, rot, right); - mid_vec := ConcatVec(mid_right_vec, mid_left_vec); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); - n := left + (right - rot); -} - -procedure {:inline 1} $1_vector_insert'#0'(m: $Mutation (Vec (#0)), i: int, e: #0) returns (m': $Mutation (Vec (#0))) { - var left_vec: Vec (#0); - var right_vec: Vec (#0); - var v: Vec (#0); - v := $Dereference(m); - if (!(i >= 0 && i <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - if (i == LenVec(v)) { - m' := $UpdateMutation(m, ExtendVec(v, e)); - } else { - left_vec := ExtendVec(SliceVec(v, 0, i), e); - right_vec := SliceVec(v, i, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); - } -} - -procedure {:inline 1} $1_vector_length'#0'(v: Vec (#0)) returns (l: int) { - l := LenVec(v); -} - -function {:inline} $1_vector_$length'#0'(v: Vec (#0)): int { - LenVec(v) -} - -procedure {:inline 1} $1_vector_borrow'#0'(v: Vec (#0), i: int) returns (dst: #0) { - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - dst := ReadVec(v, i); -} - -function {:inline} $1_vector_$borrow'#0'(v: Vec (#0), i: int): #0 { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_borrow_mut'#0'(m: $Mutation (Vec (#0)), index: int) -returns (dst: $Mutation (#0), m': $Mutation (Vec (#0))) -{ - var v: Vec (#0); - v := $Dereference(m); - if (!InRangeVec(v, index)) { - call $ExecFailureAbort(); - return; - } - dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); - m' := m; -} - -function {:inline} $1_vector_$borrow_mut'#0'(v: Vec (#0), i: int): #0 { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_destroy_empty'#0'(v: Vec (#0)) { - if (!IsEmptyVec(v)) { - call $ExecFailureAbort(); - } -} - -procedure {:inline 1} $1_vector_swap'#0'(m: $Mutation (Vec (#0)), i: int, j: int) returns (m': $Mutation (Vec (#0))) -{ - var v: Vec (#0); - v := $Dereference(m); - if (!InRangeVec(v, i) || !InRangeVec(v, j)) { - call $ExecFailureAbort(); - return; - } - m' := $UpdateMutation(m, SwapVec(v, i, j)); -} - -function {:inline} $1_vector_$swap'#0'(v: Vec (#0), i: int, j: int): Vec (#0) { - SwapVec(v, i, j) -} - -procedure {:inline 1} $1_vector_remove'#0'(m: $Mutation (Vec (#0)), i: int) returns (e: #0, m': $Mutation (Vec (#0))) -{ - var v: Vec (#0); - - v := $Dereference(m); - - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveAtVec(v, i)); -} - -procedure {:inline 1} $1_vector_swap_remove'#0'(m: $Mutation (Vec (#0)), i: int) returns (e: #0, m': $Mutation (Vec (#0))) -{ - var len: int; - var v: Vec (#0); - - v := $Dereference(m); - len := LenVec(v); - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); -} - -procedure {:inline 1} $1_vector_contains'#0'(v: Vec (#0), e: #0) returns (res: bool) { - res := $ContainsVec'#0'(v, e); -} - -procedure {:inline 1} -$1_vector_index_of'#0'(v: Vec (#0), e: #0) returns (res1: bool, res2: int) { - res2 := $IndexOfVec'#0'(v, e); - if (res2 >= 0) { - res1 := true; - } else { - res1 := false; - res2 := 0; - } -} - - -// ---------------------------------------------------------------------------------- -// Native Vector implementation for element type `address` - -// Not inlined. It appears faster this way. -function $IsEqual'vec'address''(v1: Vec (int), v2: Vec (int)): bool { - LenVec(v1) == LenVec(v2) && - (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'address'(ReadVec(v1, i), ReadVec(v2, i))) -} - -// Not inlined. -function $IsPrefix'vec'address''(v: Vec (int), prefix: Vec (int)): bool { - LenVec(v) >= LenVec(prefix) && - (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'address'(ReadVec(v, i), ReadVec(prefix, i))) -} - -// Not inlined. -function $IsSuffix'vec'address''(v: Vec (int), suffix: Vec (int)): bool { - LenVec(v) >= LenVec(suffix) && - (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'address'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) -} - -// Not inlined. -function $IsValid'vec'address''(v: Vec (int)): bool { - $IsValid'u64'(LenVec(v)) && - (forall i: int:: InRangeVec(v, i) ==> $IsValid'address'(ReadVec(v, i))) -} - - -function {:inline} $ContainsVec'address'(v: Vec (int), e: int): bool { - (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'address'(ReadVec(v, i), e)) -} - -function $IndexOfVec'address'(v: Vec (int), e: int): int; -axiom (forall v: Vec (int), e: int:: {$IndexOfVec'address'(v, e)} - (var i := $IndexOfVec'address'(v, e); - if (!$ContainsVec'address'(v, e)) then i == -1 - else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'address'(ReadVec(v, i), e) && - (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'address'(ReadVec(v, j), e)))); - - -function {:inline} $RangeVec'address'(v: Vec (int)): $Range { - $Range(0, LenVec(v)) -} - - -function {:inline} $EmptyVec'address'(): Vec (int) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_empty'address'() returns (v: Vec (int)) { - v := EmptyVec(); -} - -function {:inline} $1_vector_$empty'address'(): Vec (int) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_is_empty'address'(v: Vec (int)) returns (b: bool) { - b := IsEmptyVec(v); -} - -procedure {:inline 1} $1_vector_push_back'address'(m: $Mutation (Vec (int)), val: int) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); -} - -function {:inline} $1_vector_$push_back'address'(v: Vec (int), val: int): Vec (int) { - ExtendVec(v, val) -} - -procedure {:inline 1} $1_vector_pop_back'address'(m: $Mutation (Vec (int))) returns (e: int, m': $Mutation (Vec (int))) { - var v: Vec (int); - var len: int; - v := $Dereference(m); - len := LenVec(v); - if (len == 0) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, len-1); - m' := $UpdateMutation(m, RemoveVec(v)); -} - -procedure {:inline 1} $1_vector_append'address'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); -} - -procedure {:inline 1} $1_vector_reverse'address'(m: $Mutation (Vec (int))) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ReverseVec($Dereference(m))); -} - -procedure {:inline 1} $1_vector_reverse_append'address'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); -} - -procedure {:inline 1} $1_vector_trim_reverse'address'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - v := ReverseVec(v); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_trim'address'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_reverse_slice'address'(m: $Mutation (Vec (int)), left: int, right: int) returns (m': $Mutation (Vec (int))) { - var left_vec: Vec (int); - var mid_vec: Vec (int); - var right_vec: Vec (int); - var v: Vec (int); - if (left > right) { - call $ExecFailureAbort(); - return; - } - if (left == right) { - m' := m; - return; - } - v := $Dereference(m); - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_vec := ReverseVec(SliceVec(v, left, right)); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); -} - -procedure {:inline 1} $1_vector_rotate'address'(m: $Mutation (Vec (int)), rot: int) returns (n: int, m': $Mutation (Vec (int))) { - var v: Vec (int); - var len: int; - var left_vec: Vec (int); - var right_vec: Vec (int); - v := $Dereference(m); - if (!(rot >= 0 && rot <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, rot); - right_vec := SliceVec(v, rot, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); - n := LenVec(v) - rot; -} - -procedure {:inline 1} $1_vector_rotate_slice'address'(m: $Mutation (Vec (int)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (int))) { - var left_vec: Vec (int); - var mid_vec: Vec (int); - var right_vec: Vec (int); - var mid_left_vec: Vec (int); - var mid_right_vec: Vec (int); - var v: Vec (int); - v := $Dereference(m); - if (!(left <= rot && rot <= right)) { - call $ExecFailureAbort(); - return; - } - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - v := $Dereference(m); - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_left_vec := SliceVec(v, left, rot); - mid_right_vec := SliceVec(v, rot, right); - mid_vec := ConcatVec(mid_right_vec, mid_left_vec); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); - n := left + (right - rot); -} - -procedure {:inline 1} $1_vector_insert'address'(m: $Mutation (Vec (int)), i: int, e: int) returns (m': $Mutation (Vec (int))) { - var left_vec: Vec (int); - var right_vec: Vec (int); - var v: Vec (int); - v := $Dereference(m); - if (!(i >= 0 && i <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - if (i == LenVec(v)) { - m' := $UpdateMutation(m, ExtendVec(v, e)); - } else { - left_vec := ExtendVec(SliceVec(v, 0, i), e); - right_vec := SliceVec(v, i, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); - } -} - -procedure {:inline 1} $1_vector_length'address'(v: Vec (int)) returns (l: int) { - l := LenVec(v); -} - -function {:inline} $1_vector_$length'address'(v: Vec (int)): int { - LenVec(v) -} - -procedure {:inline 1} $1_vector_borrow'address'(v: Vec (int), i: int) returns (dst: int) { - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - dst := ReadVec(v, i); -} - -function {:inline} $1_vector_$borrow'address'(v: Vec (int), i: int): int { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_borrow_mut'address'(m: $Mutation (Vec (int)), index: int) -returns (dst: $Mutation (int), m': $Mutation (Vec (int))) -{ - var v: Vec (int); - v := $Dereference(m); - if (!InRangeVec(v, index)) { - call $ExecFailureAbort(); - return; - } - dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); - m' := m; -} - -function {:inline} $1_vector_$borrow_mut'address'(v: Vec (int), i: int): int { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_destroy_empty'address'(v: Vec (int)) { - if (!IsEmptyVec(v)) { - call $ExecFailureAbort(); - } -} - -procedure {:inline 1} $1_vector_swap'address'(m: $Mutation (Vec (int)), i: int, j: int) returns (m': $Mutation (Vec (int))) -{ - var v: Vec (int); - v := $Dereference(m); - if (!InRangeVec(v, i) || !InRangeVec(v, j)) { - call $ExecFailureAbort(); - return; - } - m' := $UpdateMutation(m, SwapVec(v, i, j)); -} - -function {:inline} $1_vector_$swap'address'(v: Vec (int), i: int, j: int): Vec (int) { - SwapVec(v, i, j) -} - -procedure {:inline 1} $1_vector_remove'address'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) -{ - var v: Vec (int); - - v := $Dereference(m); - - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveAtVec(v, i)); -} - -procedure {:inline 1} $1_vector_swap_remove'address'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) -{ - var len: int; - var v: Vec (int); - - v := $Dereference(m); - len := LenVec(v); - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); -} - -procedure {:inline 1} $1_vector_contains'address'(v: Vec (int), e: int) returns (res: bool) { - res := $ContainsVec'address'(v, e); -} - -procedure {:inline 1} -$1_vector_index_of'address'(v: Vec (int), e: int) returns (res1: bool, res2: int) { - res2 := $IndexOfVec'address'(v, e); - if (res2 >= 0) { - res1 := true; - } else { - res1 := false; - res2 := 0; - } -} - - -// ---------------------------------------------------------------------------------- -// Native Vector implementation for element type `u8` - -// Not inlined. It appears faster this way. -function $IsEqual'vec'u8''(v1: Vec (int), v2: Vec (int)): bool { - LenVec(v1) == LenVec(v2) && - (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'u8'(ReadVec(v1, i), ReadVec(v2, i))) -} - -// Not inlined. -function $IsPrefix'vec'u8''(v: Vec (int), prefix: Vec (int)): bool { - LenVec(v) >= LenVec(prefix) && - (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'u8'(ReadVec(v, i), ReadVec(prefix, i))) -} - -// Not inlined. -function $IsSuffix'vec'u8''(v: Vec (int), suffix: Vec (int)): bool { - LenVec(v) >= LenVec(suffix) && - (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'u8'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) -} - -// Not inlined. -function $IsValid'vec'u8''(v: Vec (int)): bool { - $IsValid'u64'(LenVec(v)) && - (forall i: int:: InRangeVec(v, i) ==> $IsValid'u8'(ReadVec(v, i))) -} - - -function {:inline} $ContainsVec'u8'(v: Vec (int), e: int): bool { - (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'u8'(ReadVec(v, i), e)) -} - -function $IndexOfVec'u8'(v: Vec (int), e: int): int; -axiom (forall v: Vec (int), e: int:: {$IndexOfVec'u8'(v, e)} - (var i := $IndexOfVec'u8'(v, e); - if (!$ContainsVec'u8'(v, e)) then i == -1 - else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'u8'(ReadVec(v, i), e) && - (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'u8'(ReadVec(v, j), e)))); - - -function {:inline} $RangeVec'u8'(v: Vec (int)): $Range { - $Range(0, LenVec(v)) -} - - -function {:inline} $EmptyVec'u8'(): Vec (int) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_empty'u8'() returns (v: Vec (int)) { - v := EmptyVec(); -} - -function {:inline} $1_vector_$empty'u8'(): Vec (int) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_is_empty'u8'(v: Vec (int)) returns (b: bool) { - b := IsEmptyVec(v); -} - -procedure {:inline 1} $1_vector_push_back'u8'(m: $Mutation (Vec (int)), val: int) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); -} - -function {:inline} $1_vector_$push_back'u8'(v: Vec (int), val: int): Vec (int) { - ExtendVec(v, val) -} - -procedure {:inline 1} $1_vector_pop_back'u8'(m: $Mutation (Vec (int))) returns (e: int, m': $Mutation (Vec (int))) { - var v: Vec (int); - var len: int; - v := $Dereference(m); - len := LenVec(v); - if (len == 0) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, len-1); - m' := $UpdateMutation(m, RemoveVec(v)); -} - -procedure {:inline 1} $1_vector_append'u8'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); -} - -procedure {:inline 1} $1_vector_reverse'u8'(m: $Mutation (Vec (int))) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ReverseVec($Dereference(m))); -} - -procedure {:inline 1} $1_vector_reverse_append'u8'(m: $Mutation (Vec (int)), other: Vec (int)) returns (m': $Mutation (Vec (int))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); -} - -procedure {:inline 1} $1_vector_trim_reverse'u8'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - v := ReverseVec(v); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_trim'u8'(m: $Mutation (Vec (int)), new_len: int) returns (v: (Vec (int)), m': $Mutation (Vec (int))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_reverse_slice'u8'(m: $Mutation (Vec (int)), left: int, right: int) returns (m': $Mutation (Vec (int))) { - var left_vec: Vec (int); - var mid_vec: Vec (int); - var right_vec: Vec (int); - var v: Vec (int); - if (left > right) { - call $ExecFailureAbort(); - return; - } - if (left == right) { - m' := m; - return; - } - v := $Dereference(m); - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_vec := ReverseVec(SliceVec(v, left, right)); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); -} - -procedure {:inline 1} $1_vector_rotate'u8'(m: $Mutation (Vec (int)), rot: int) returns (n: int, m': $Mutation (Vec (int))) { - var v: Vec (int); - var len: int; - var left_vec: Vec (int); - var right_vec: Vec (int); - v := $Dereference(m); - if (!(rot >= 0 && rot <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, rot); - right_vec := SliceVec(v, rot, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); - n := LenVec(v) - rot; -} - -procedure {:inline 1} $1_vector_rotate_slice'u8'(m: $Mutation (Vec (int)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (int))) { - var left_vec: Vec (int); - var mid_vec: Vec (int); - var right_vec: Vec (int); - var mid_left_vec: Vec (int); - var mid_right_vec: Vec (int); - var v: Vec (int); - v := $Dereference(m); - if (!(left <= rot && rot <= right)) { - call $ExecFailureAbort(); - return; - } - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - v := $Dereference(m); - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_left_vec := SliceVec(v, left, rot); - mid_right_vec := SliceVec(v, rot, right); - mid_vec := ConcatVec(mid_right_vec, mid_left_vec); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); - n := left + (right - rot); -} - -procedure {:inline 1} $1_vector_insert'u8'(m: $Mutation (Vec (int)), i: int, e: int) returns (m': $Mutation (Vec (int))) { - var left_vec: Vec (int); - var right_vec: Vec (int); - var v: Vec (int); - v := $Dereference(m); - if (!(i >= 0 && i <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - if (i == LenVec(v)) { - m' := $UpdateMutation(m, ExtendVec(v, e)); - } else { - left_vec := ExtendVec(SliceVec(v, 0, i), e); - right_vec := SliceVec(v, i, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); - } -} - -procedure {:inline 1} $1_vector_length'u8'(v: Vec (int)) returns (l: int) { - l := LenVec(v); -} - -function {:inline} $1_vector_$length'u8'(v: Vec (int)): int { - LenVec(v) -} - -procedure {:inline 1} $1_vector_borrow'u8'(v: Vec (int), i: int) returns (dst: int) { - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - dst := ReadVec(v, i); -} - -function {:inline} $1_vector_$borrow'u8'(v: Vec (int), i: int): int { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_borrow_mut'u8'(m: $Mutation (Vec (int)), index: int) -returns (dst: $Mutation (int), m': $Mutation (Vec (int))) -{ - var v: Vec (int); - v := $Dereference(m); - if (!InRangeVec(v, index)) { - call $ExecFailureAbort(); - return; - } - dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); - m' := m; -} - -function {:inline} $1_vector_$borrow_mut'u8'(v: Vec (int), i: int): int { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_destroy_empty'u8'(v: Vec (int)) { - if (!IsEmptyVec(v)) { - call $ExecFailureAbort(); - } -} - -procedure {:inline 1} $1_vector_swap'u8'(m: $Mutation (Vec (int)), i: int, j: int) returns (m': $Mutation (Vec (int))) -{ - var v: Vec (int); - v := $Dereference(m); - if (!InRangeVec(v, i) || !InRangeVec(v, j)) { - call $ExecFailureAbort(); - return; - } - m' := $UpdateMutation(m, SwapVec(v, i, j)); -} - -function {:inline} $1_vector_$swap'u8'(v: Vec (int), i: int, j: int): Vec (int) { - SwapVec(v, i, j) -} - -procedure {:inline 1} $1_vector_remove'u8'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) -{ - var v: Vec (int); - - v := $Dereference(m); - - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveAtVec(v, i)); -} - -procedure {:inline 1} $1_vector_swap_remove'u8'(m: $Mutation (Vec (int)), i: int) returns (e: int, m': $Mutation (Vec (int))) -{ - var len: int; - var v: Vec (int); - - v := $Dereference(m); - len := LenVec(v); - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); -} - -procedure {:inline 1} $1_vector_contains'u8'(v: Vec (int), e: int) returns (res: bool) { - res := $ContainsVec'u8'(v, e); -} - -procedure {:inline 1} -$1_vector_index_of'u8'(v: Vec (int), e: int) returns (res1: bool, res2: int) { - res2 := $IndexOfVec'u8'(v, e); - if (res2 >= 0) { - res1 := true; - } else { - res1 := false; - res2 := 0; - } -} - - -// ---------------------------------------------------------------------------------- -// Native Vector implementation for element type `bv8` - -// Not inlined. It appears faster this way. -function $IsEqual'vec'bv8''(v1: Vec (bv8), v2: Vec (bv8)): bool { - LenVec(v1) == LenVec(v2) && - (forall i: int:: InRangeVec(v1, i) ==> $IsEqual'bv8'(ReadVec(v1, i), ReadVec(v2, i))) -} - -// Not inlined. -function $IsPrefix'vec'bv8''(v: Vec (bv8), prefix: Vec (bv8)): bool { - LenVec(v) >= LenVec(prefix) && - (forall i: int:: InRangeVec(prefix, i) ==> $IsEqual'bv8'(ReadVec(v, i), ReadVec(prefix, i))) -} - -// Not inlined. -function $IsSuffix'vec'bv8''(v: Vec (bv8), suffix: Vec (bv8)): bool { - LenVec(v) >= LenVec(suffix) && - (forall i: int:: InRangeVec(suffix, i) ==> $IsEqual'bv8'(ReadVec(v, LenVec(v) - LenVec(suffix) + i), ReadVec(suffix, i))) -} - -// Not inlined. -function $IsValid'vec'bv8''(v: Vec (bv8)): bool { - $IsValid'u64'(LenVec(v)) && - (forall i: int:: InRangeVec(v, i) ==> $IsValid'bv8'(ReadVec(v, i))) -} - - -function {:inline} $ContainsVec'bv8'(v: Vec (bv8), e: bv8): bool { - (exists i: int :: $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'bv8'(ReadVec(v, i), e)) -} - -function $IndexOfVec'bv8'(v: Vec (bv8), e: bv8): int; -axiom (forall v: Vec (bv8), e: bv8:: {$IndexOfVec'bv8'(v, e)} - (var i := $IndexOfVec'bv8'(v, e); - if (!$ContainsVec'bv8'(v, e)) then i == -1 - else $IsValid'u64'(i) && InRangeVec(v, i) && $IsEqual'bv8'(ReadVec(v, i), e) && - (forall j: int :: $IsValid'u64'(j) && j >= 0 && j < i ==> !$IsEqual'bv8'(ReadVec(v, j), e)))); - - -function {:inline} $RangeVec'bv8'(v: Vec (bv8)): $Range { - $Range(0, LenVec(v)) -} - - -function {:inline} $EmptyVec'bv8'(): Vec (bv8) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_empty'bv8'() returns (v: Vec (bv8)) { - v := EmptyVec(); -} - -function {:inline} $1_vector_$empty'bv8'(): Vec (bv8) { - EmptyVec() -} - -procedure {:inline 1} $1_vector_is_empty'bv8'(v: Vec (bv8)) returns (b: bool) { - b := IsEmptyVec(v); -} - -procedure {:inline 1} $1_vector_push_back'bv8'(m: $Mutation (Vec (bv8)), val: bv8) returns (m': $Mutation (Vec (bv8))) { - m' := $UpdateMutation(m, ExtendVec($Dereference(m), val)); -} - -function {:inline} $1_vector_$push_back'bv8'(v: Vec (bv8), val: bv8): Vec (bv8) { - ExtendVec(v, val) -} - -procedure {:inline 1} $1_vector_pop_back'bv8'(m: $Mutation (Vec (bv8))) returns (e: bv8, m': $Mutation (Vec (bv8))) { - var v: Vec (bv8); - var len: int; - v := $Dereference(m); - len := LenVec(v); - if (len == 0) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, len-1); - m' := $UpdateMutation(m, RemoveVec(v)); -} - -procedure {:inline 1} $1_vector_append'bv8'(m: $Mutation (Vec (bv8)), other: Vec (bv8)) returns (m': $Mutation (Vec (bv8))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), other)); -} - -procedure {:inline 1} $1_vector_reverse'bv8'(m: $Mutation (Vec (bv8))) returns (m': $Mutation (Vec (bv8))) { - m' := $UpdateMutation(m, ReverseVec($Dereference(m))); -} - -procedure {:inline 1} $1_vector_reverse_append'bv8'(m: $Mutation (Vec (bv8)), other: Vec (bv8)) returns (m': $Mutation (Vec (bv8))) { - m' := $UpdateMutation(m, ConcatVec($Dereference(m), ReverseVec(other))); -} - -procedure {:inline 1} $1_vector_trim_reverse'bv8'(m: $Mutation (Vec (bv8)), new_len: int) returns (v: (Vec (bv8)), m': $Mutation (Vec (bv8))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - v := ReverseVec(v); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_trim'bv8'(m: $Mutation (Vec (bv8)), new_len: int) returns (v: (Vec (bv8)), m': $Mutation (Vec (bv8))) { - var len: int; - v := $Dereference(m); - if (LenVec(v) < new_len) { - call $ExecFailureAbort(); - return; - } - v := SliceVec(v, new_len, LenVec(v)); - m' := $UpdateMutation(m, SliceVec($Dereference(m), 0, new_len)); -} - -procedure {:inline 1} $1_vector_reverse_slice'bv8'(m: $Mutation (Vec (bv8)), left: int, right: int) returns (m': $Mutation (Vec (bv8))) { - var left_vec: Vec (bv8); - var mid_vec: Vec (bv8); - var right_vec: Vec (bv8); - var v: Vec (bv8); - if (left > right) { - call $ExecFailureAbort(); - return; - } - if (left == right) { - m' := m; - return; - } - v := $Dereference(m); - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_vec := ReverseVec(SliceVec(v, left, right)); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); -} - -procedure {:inline 1} $1_vector_rotate'bv8'(m: $Mutation (Vec (bv8)), rot: int) returns (n: int, m': $Mutation (Vec (bv8))) { - var v: Vec (bv8); - var len: int; - var left_vec: Vec (bv8); - var right_vec: Vec (bv8); - v := $Dereference(m); - if (!(rot >= 0 && rot <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - left_vec := SliceVec(v, 0, rot); - right_vec := SliceVec(v, rot, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(right_vec, left_vec)); - n := LenVec(v) - rot; -} - -procedure {:inline 1} $1_vector_rotate_slice'bv8'(m: $Mutation (Vec (bv8)), left: int, rot: int, right: int) returns (n: int, m': $Mutation (Vec (bv8))) { - var left_vec: Vec (bv8); - var mid_vec: Vec (bv8); - var right_vec: Vec (bv8); - var mid_left_vec: Vec (bv8); - var mid_right_vec: Vec (bv8); - var v: Vec (bv8); - v := $Dereference(m); - if (!(left <= rot && rot <= right)) { - call $ExecFailureAbort(); - return; - } - if (!(right >= 0 && right <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - v := $Dereference(m); - left_vec := SliceVec(v, 0, left); - right_vec := SliceVec(v, right, LenVec(v)); - mid_left_vec := SliceVec(v, left, rot); - mid_right_vec := SliceVec(v, rot, right); - mid_vec := ConcatVec(mid_right_vec, mid_left_vec); - m' := $UpdateMutation(m, ConcatVec(left_vec, ConcatVec(mid_vec, right_vec))); - n := left + (right - rot); -} - -procedure {:inline 1} $1_vector_insert'bv8'(m: $Mutation (Vec (bv8)), i: int, e: bv8) returns (m': $Mutation (Vec (bv8))) { - var left_vec: Vec (bv8); - var right_vec: Vec (bv8); - var v: Vec (bv8); - v := $Dereference(m); - if (!(i >= 0 && i <= LenVec(v))) { - call $ExecFailureAbort(); - return; - } - if (i == LenVec(v)) { - m' := $UpdateMutation(m, ExtendVec(v, e)); - } else { - left_vec := ExtendVec(SliceVec(v, 0, i), e); - right_vec := SliceVec(v, i, LenVec(v)); - m' := $UpdateMutation(m, ConcatVec(left_vec, right_vec)); - } -} - -procedure {:inline 1} $1_vector_length'bv8'(v: Vec (bv8)) returns (l: int) { - l := LenVec(v); -} - -function {:inline} $1_vector_$length'bv8'(v: Vec (bv8)): int { - LenVec(v) -} - -procedure {:inline 1} $1_vector_borrow'bv8'(v: Vec (bv8), i: int) returns (dst: bv8) { - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - dst := ReadVec(v, i); -} - -function {:inline} $1_vector_$borrow'bv8'(v: Vec (bv8), i: int): bv8 { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_borrow_mut'bv8'(m: $Mutation (Vec (bv8)), index: int) -returns (dst: $Mutation (bv8), m': $Mutation (Vec (bv8))) -{ - var v: Vec (bv8); - v := $Dereference(m); - if (!InRangeVec(v, index)) { - call $ExecFailureAbort(); - return; - } - dst := $Mutation(m->l, ExtendVec(m->p, index), ReadVec(v, index)); - m' := m; -} - -function {:inline} $1_vector_$borrow_mut'bv8'(v: Vec (bv8), i: int): bv8 { - ReadVec(v, i) -} - -procedure {:inline 1} $1_vector_destroy_empty'bv8'(v: Vec (bv8)) { - if (!IsEmptyVec(v)) { - call $ExecFailureAbort(); - } -} - -procedure {:inline 1} $1_vector_swap'bv8'(m: $Mutation (Vec (bv8)), i: int, j: int) returns (m': $Mutation (Vec (bv8))) -{ - var v: Vec (bv8); - v := $Dereference(m); - if (!InRangeVec(v, i) || !InRangeVec(v, j)) { - call $ExecFailureAbort(); - return; - } - m' := $UpdateMutation(m, SwapVec(v, i, j)); -} - -function {:inline} $1_vector_$swap'bv8'(v: Vec (bv8), i: int, j: int): Vec (bv8) { - SwapVec(v, i, j) -} - -procedure {:inline 1} $1_vector_remove'bv8'(m: $Mutation (Vec (bv8)), i: int) returns (e: bv8, m': $Mutation (Vec (bv8))) -{ - var v: Vec (bv8); - - v := $Dereference(m); - - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveAtVec(v, i)); -} - -procedure {:inline 1} $1_vector_swap_remove'bv8'(m: $Mutation (Vec (bv8)), i: int) returns (e: bv8, m': $Mutation (Vec (bv8))) -{ - var len: int; - var v: Vec (bv8); - - v := $Dereference(m); - len := LenVec(v); - if (!InRangeVec(v, i)) { - call $ExecFailureAbort(); - return; - } - e := ReadVec(v, i); - m' := $UpdateMutation(m, RemoveVec(SwapVec(v, i, len-1))); -} - -procedure {:inline 1} $1_vector_contains'bv8'(v: Vec (bv8), e: bv8) returns (res: bool) { - res := $ContainsVec'bv8'(v, e); -} - -procedure {:inline 1} -$1_vector_index_of'bv8'(v: Vec (bv8), e: bv8) returns (res1: bool, res2: int) { - res2 := $IndexOfVec'bv8'(v, e); - if (res2 >= 0) { - res1 := true; - } else { - res1 := false; - res2 := 0; - } -} - - -// ================================================================================== -// Native Table - -// ---------------------------------------------------------------------------------- -// Native Table key encoding for type `vec'u8'` - -function $EncodeKey'vec'u8''(k: Vec (int)): int; -axiom ( - forall k1, k2: Vec (int) :: {$EncodeKey'vec'u8''(k1), $EncodeKey'vec'u8''(k2)} - $IsEqual'vec'u8''(k1, k2) <==> $EncodeKey'vec'u8''(k1) == $EncodeKey'vec'u8''(k2) -); - - -// ---------------------------------------------------------------------------------- -// Native Table implementation for type `(vec'u8',$1_timelock_TimelockTransaction)` - -function $IsEqual'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(t1: Table int ($1_timelock_TimelockTransaction), t2: Table int ($1_timelock_TimelockTransaction)): bool { - LenTable(t1) == LenTable(t2) && - (forall k: int :: ContainsTable(t1, k) <==> ContainsTable(t2, k)) && - (forall k: int :: ContainsTable(t1, k) ==> GetTable(t1, k) == GetTable(t2, k)) && - (forall k: int :: ContainsTable(t2, k) ==> GetTable(t1, k) == GetTable(t2, k)) -} - -// Not inlined. -function $IsValid'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(t: Table int ($1_timelock_TimelockTransaction)): bool { - $IsValid'u64'(LenTable(t)) && - (forall i: int:: ContainsTable(t, i) ==> $IsValid'$1_timelock_TimelockTransaction'(GetTable(t, i))) -} -procedure {:inline 2} $1_table_new'vec'u8'_$1_timelock_TimelockTransaction'() returns (v: Table int ($1_timelock_TimelockTransaction)) { - v := EmptyTable(); -} -procedure {:inline 2} $1_table_destroy_known_empty_unsafe'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction)) { - if (LenTable(t) != 0) { - call $Abort($StdError(1/*INVALID_STATE*/, 102/*ENOT_EMPTY*/)); - } -} -procedure {:inline 2} $1_table_contains'vec'u8'_$1_timelock_TimelockTransaction'(t: (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)) returns (r: bool) { - r := ContainsTable(t, $EncodeKey'vec'u8''(k)); -} -procedure {:inline 2} $1_table_add'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int), v: $1_timelock_TimelockTransaction) returns (m': $Mutation(Table int ($1_timelock_TimelockTransaction))) { - var enc_k: int; - var t: Table int ($1_timelock_TimelockTransaction); - enc_k := $EncodeKey'vec'u8''(k); - t := $Dereference(m); - if (ContainsTable(t, enc_k)) { - call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 100/*EALREADY_EXISTS*/)); - } else { - m' := $UpdateMutation(m, AddTable(t, enc_k, v)); - } -} -procedure {:inline 2} $1_table_upsert'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int), v: $1_timelock_TimelockTransaction) returns (m': $Mutation(Table int ($1_timelock_TimelockTransaction))) { - var enc_k: int; - var t: Table int ($1_timelock_TimelockTransaction); - enc_k := $EncodeKey'vec'u8''(k); - t := $Dereference(m); - if (ContainsTable(t, enc_k)) { - m' := $UpdateMutation(m, UpdateTable(t, enc_k, v)); - } else { - m' := $UpdateMutation(m, AddTable(t, enc_k, v)); - } -} -procedure {:inline 2} $1_table_remove'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)) -returns (v: $1_timelock_TimelockTransaction, m': $Mutation(Table int ($1_timelock_TimelockTransaction))) { - var enc_k: int; - var t: Table int ($1_timelock_TimelockTransaction); - enc_k := $EncodeKey'vec'u8''(k); - t := $Dereference(m); - if (!ContainsTable(t, enc_k)) { - call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 101/*ENOT_FOUND*/)); - } else { - v := GetTable(t, enc_k); - m' := $UpdateMutation(m, RemoveTable(t, enc_k)); - } -} -procedure {:inline 2} $1_table_borrow'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int)) returns (v: $1_timelock_TimelockTransaction) { - var enc_k: int; - enc_k := $EncodeKey'vec'u8''(k); - if (!ContainsTable(t, enc_k)) { - call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 101/*ENOT_FOUND*/)); - } else { - v := GetTable(t, $EncodeKey'vec'u8''(k)); - } -} -procedure {:inline 2} $1_table_borrow_mut'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)) -returns (dst: $Mutation ($1_timelock_TimelockTransaction), m': $Mutation (Table int ($1_timelock_TimelockTransaction))) { - var enc_k: int; - var t: Table int ($1_timelock_TimelockTransaction); - enc_k := $EncodeKey'vec'u8''(k); - t := $Dereference(m); - if (!ContainsTable(t, enc_k)) { - call $Abort($StdError(7/*INVALID_ARGUMENTS*/, 101/*ENOT_FOUND*/)); - } else { - dst := $Mutation(m->l, ExtendVec(m->p, enc_k), GetTable(t, enc_k)); - m' := m; - } -} -procedure {:inline 2} $1_table_borrow_mut_with_default'vec'u8'_$1_timelock_TimelockTransaction'(m: $Mutation (Table int ($1_timelock_TimelockTransaction)), k: Vec (int), default: $1_timelock_TimelockTransaction) -returns (dst: $Mutation ($1_timelock_TimelockTransaction), m': $Mutation (Table int ($1_timelock_TimelockTransaction))) { - var enc_k: int; - var t: Table int ($1_timelock_TimelockTransaction); - var t': Table int ($1_timelock_TimelockTransaction); - enc_k := $EncodeKey'vec'u8''(k); - t := $Dereference(m); - if (!ContainsTable(t, enc_k)) { - m' := $UpdateMutation(m, AddTable(t, enc_k, default)); - t' := $Dereference(m'); - dst := $Mutation(m'->l, ExtendVec(m'->p, enc_k), GetTable(t', enc_k)); - } else { - dst := $Mutation(m->l, ExtendVec(m->p, enc_k), GetTable(t, enc_k)); - m' := m; - } -} -procedure {:inline 2} $1_table_borrow_with_default'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int), default: $1_timelock_TimelockTransaction) returns (v: $1_timelock_TimelockTransaction) { - var enc_k: int; - enc_k := $EncodeKey'vec'u8''(k); - if (!ContainsTable(t, enc_k)) { - v := default; - } else { - v := GetTable(t, $EncodeKey'vec'u8''(k)); - } -} -function {:inline} $1_table_spec_contains'vec'u8'_$1_timelock_TimelockTransaction'(t: (Table int ($1_timelock_TimelockTransaction)), k: Vec (int)): bool { - ContainsTable(t, $EncodeKey'vec'u8''(k)) -} -function {:inline} $1_table_spec_set'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int), v: $1_timelock_TimelockTransaction): Table int ($1_timelock_TimelockTransaction) { - (var enc_k := $EncodeKey'vec'u8''(k); - if (ContainsTable(t, enc_k)) then - UpdateTable(t, enc_k, v) - else - AddTable(t, enc_k, v)) -} -function {:inline} $1_table_spec_remove'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int)): Table int ($1_timelock_TimelockTransaction) { - RemoveTable(t, $EncodeKey'vec'u8''(k)) -} -function {:inline} $1_table_spec_get'vec'u8'_$1_timelock_TimelockTransaction'(t: Table int ($1_timelock_TimelockTransaction), k: Vec (int)): $1_timelock_TimelockTransaction { - GetTable(t, $EncodeKey'vec'u8''(k)) -} - - - -// ================================================================================== -// Native Hash - -// Hash is modeled as an otherwise uninterpreted injection. -// In truth, it is not an injection since the domain has greater cardinality -// (arbitrary length vectors) than the co-domain (vectors of length 32). But it is -// common to assume in code there are no hash collisions in practice. Fortunately, -// Boogie is not smart enough to recognized that there is an inconsistency. -// FIXME: If we were using a reliable extensional theory of arrays, and if we could use == -// instead of $IsEqual, we might be able to avoid so many quantified formulas by -// using a sha2_inverse function in the ensures conditions of Hash_sha2_256 to -// assert that sha2/3 are injections without using global quantified axioms. - - -function $1_hash_sha2(val: Vec int): Vec int; - -// This says that Hash_sha2 is bijective. -axiom (forall v1,v2: Vec int :: {$1_hash_sha2(v1), $1_hash_sha2(v2)} - $IsEqual'vec'u8''(v1, v2) <==> $IsEqual'vec'u8''($1_hash_sha2(v1), $1_hash_sha2(v2))); - -procedure $1_hash_sha2_256(val: Vec int) returns (res: Vec int); -ensures res == $1_hash_sha2(val); // returns Hash_sha2 Value -ensures $IsValid'vec'u8''(res); // result is a legal vector of U8s. -ensures LenVec(res) == 32; // result is 32 bytes. - -// Spec version of Move native function. -function {:inline} $1_hash_$sha2_256(val: Vec int): Vec int { - $1_hash_sha2(val) -} - -// similarly for Hash_sha3 -function $1_hash_sha3(val: Vec int): Vec int; - -axiom (forall v1,v2: Vec int :: {$1_hash_sha3(v1), $1_hash_sha3(v2)} - $IsEqual'vec'u8''(v1, v2) <==> $IsEqual'vec'u8''($1_hash_sha3(v1), $1_hash_sha3(v2))); - -procedure $1_hash_sha3_256(val: Vec int) returns (res: Vec int); -ensures res == $1_hash_sha3(val); // returns Hash_sha3 Value -ensures $IsValid'vec'u8''(res); // result is a legal vector of U8s. -ensures LenVec(res) == 32; // result is 32 bytes. - -// Spec version of Move native function. -function {:inline} $1_hash_$sha3_256(val: Vec int): Vec int { - $1_hash_sha3(val) -} - -// ================================================================================== -// Native string - -// TODO: correct implementation of strings - -procedure {:inline 1} $1_string_internal_check_utf8(x: Vec int) returns (r: bool) { -} - -procedure {:inline 1} $1_string_internal_sub_string(x: Vec int, i: int, j: int) returns (r: Vec int) { -} - -procedure {:inline 1} $1_string_internal_index_of(x: Vec int, y: Vec int) returns (r: int) { -} - -procedure {:inline 1} $1_string_internal_is_char_boundary(x: Vec int, i: int) returns (r: bool) { -} - - - - -// ================================================================================== -// Native diem_account - -procedure {:inline 1} $1_DiemAccount_create_signer( - addr: int -) returns (signer: $signer) { - // A signer is currently identical to an address. - signer := $signer(addr); -} - -procedure {:inline 1} $1_DiemAccount_destroy_signer( - signer: $signer -) { - return; -} - -// ================================================================================== -// Native account - -procedure {:inline 1} $1_Account_create_signer( - addr: int -) returns (signer: $signer) { - // A signer is currently identical to an address. - signer := $signer(addr); -} - -// ================================================================================== -// Native Signer - -datatype $signer { - $signer($addr: int), - $permissioned_signer($addr: int, $permission_addr: int) -} - -function {:inline} $IsValid'signer'(s: $signer): bool { - if s is $signer then - $IsValid'address'(s->$addr) - else - $IsValid'address'(s->$addr) && - $IsValid'address'(s->$permission_addr) -} - -function {:inline} $IsEqual'signer'(s1: $signer, s2: $signer): bool { - if s1 is $signer && s2 is $signer then - s1 == s2 - else if s1 is $permissioned_signer && s2 is $permissioned_signer then - s1 == s2 - else - false -} - -procedure {:inline 1} $1_signer_borrow_address(signer: $signer) returns (res: int) { - res := signer->$addr; -} - -function {:inline} $1_signer_$borrow_address(signer: $signer): int -{ - signer->$addr -} - -function $1_signer_is_txn_signer(s: $signer): bool; - -function $1_signer_is_txn_signer_addr(a: int): bool; - - -// ================================================================================== -// Native signature - -// Signature related functionality is handled via uninterpreted functions. This is sound -// currently because we verify every code path based on signature verification with -// an arbitrary interpretation. - -function $1_Signature_$ed25519_validate_pubkey(public_key: Vec int): bool; -function $1_Signature_$ed25519_verify(signature: Vec int, public_key: Vec int, message: Vec int): bool; - -// Needed because we do not have extensional equality: -axiom (forall k1, k2: Vec int :: - {$1_Signature_$ed25519_validate_pubkey(k1), $1_Signature_$ed25519_validate_pubkey(k2)} - $IsEqual'vec'u8''(k1, k2) ==> $1_Signature_$ed25519_validate_pubkey(k1) == $1_Signature_$ed25519_validate_pubkey(k2)); -axiom (forall s1, s2, k1, k2, m1, m2: Vec int :: - {$1_Signature_$ed25519_verify(s1, k1, m1), $1_Signature_$ed25519_verify(s2, k2, m2)} - $IsEqual'vec'u8''(s1, s2) && $IsEqual'vec'u8''(k1, k2) && $IsEqual'vec'u8''(m1, m2) - ==> $1_Signature_$ed25519_verify(s1, k1, m1) == $1_Signature_$ed25519_verify(s2, k2, m2)); - - -procedure {:inline 1} $1_Signature_ed25519_validate_pubkey(public_key: Vec int) returns (res: bool) { - res := $1_Signature_$ed25519_validate_pubkey(public_key); -} - -procedure {:inline 1} $1_Signature_ed25519_verify( - signature: Vec int, public_key: Vec int, message: Vec int) returns (res: bool) { - res := $1_Signature_$ed25519_verify(signature, public_key, message); -} - - -// ================================================================================== -// Native bcs::serialize - -// ---------------------------------------------------------------------------------- -// Native BCS implementation for element type `u64` - -// Serialize is modeled as an uninterpreted function, with an additional -// axiom to say it's an injection. - -function $1_bcs_serialize'u64'(v: int): Vec int; - -axiom (forall v1, v2: int :: {$1_bcs_serialize'u64'(v1), $1_bcs_serialize'u64'(v2)} - $IsEqual'u64'(v1, v2) <==> $IsEqual'vec'u8''($1_bcs_serialize'u64'(v1), $1_bcs_serialize'u64'(v2))); - -// This says that serialize returns a non-empty vec - -axiom (forall v: int :: {$1_bcs_serialize'u64'(v)} - ( var r := $1_bcs_serialize'u64'(v); $IsValid'vec'u8''(r) && LenVec(r) > 0 )); - - -procedure $1_bcs_to_bytes'u64'(v: int) returns (res: Vec int); -ensures res == $1_bcs_serialize'u64'(v); - -function {:inline} $1_bcs_$to_bytes'u64'(v: int): Vec int { - $1_bcs_serialize'u64'(v) -} - - - - - -// ================================================================================== -// Native Event module - - - -procedure {:inline 1} $InitEventStore() { -} - -// ============================================================================================ -// Type Reflection on Type Parameters - -datatype $TypeParamInfo { - $TypeParamBool(), - $TypeParamU8(), - $TypeParamU16(), - $TypeParamU32(), - $TypeParamU64(), - $TypeParamU128(), - $TypeParamU256(), - $TypeParamAddress(), - $TypeParamSigner(), - $TypeParamVector(e: $TypeParamInfo), - $TypeParamStruct(a: int, m: Vec int, s: Vec int) -} - - - -//================================== -// Begin Translation - -function $TypeName(t: $TypeParamInfo): Vec int; -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamBool ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 98][1 := 111][2 := 111][3 := 108], 4))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 98][1 := 111][2 := 111][3 := 108], 4)) ==> t is $TypeParamBool); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU8 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 56], 2))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 56], 2)) ==> t is $TypeParamU8); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU16 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 54], 3))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 54], 3)) ==> t is $TypeParamU16); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU32 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 51][2 := 50], 3))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 51][2 := 50], 3)) ==> t is $TypeParamU32); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU64 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 54][2 := 52], 3))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 54][2 := 52], 3)) ==> t is $TypeParamU64); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU128 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 50][3 := 56], 4))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 49][2 := 50][3 := 56], 4)) ==> t is $TypeParamU128); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamU256 ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 50][2 := 53][3 := 54], 4))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 117][1 := 50][2 := 53][3 := 54], 4)) ==> t is $TypeParamU256); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamAddress ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 97][1 := 100][2 := 100][3 := 114][4 := 101][5 := 115][6 := 115], 7))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 97][1 := 100][2 := 100][3 := 114][4 := 101][5 := 115][6 := 115], 7)) ==> t is $TypeParamAddress); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamSigner ==> $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 115][1 := 105][2 := 103][3 := 110][4 := 101][5 := 114], 6))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsEqual'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 115][1 := 105][2 := 103][3 := 110][4 := 101][5 := 114], 6)) ==> t is $TypeParamSigner); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamVector ==> $IsEqual'vec'u8''($TypeName(t), ConcatVec(ConcatVec(Vec(DefaultVecMap()[0 := 118][1 := 101][2 := 99][3 := 116][4 := 111][5 := 114][6 := 60], 7), $TypeName(t->e)), Vec(DefaultVecMap()[0 := 62], 1)))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} ($IsPrefix'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 118][1 := 101][2 := 99][3 := 116][4 := 111][5 := 114][6 := 60], 7)) && $IsSuffix'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 62], 1))) ==> t is $TypeParamVector); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} t is $TypeParamStruct ==> $IsEqual'vec'u8''($TypeName(t), ConcatVec(ConcatVec(ConcatVec(ConcatVec(ConcatVec(Vec(DefaultVecMap()[0 := 48][1 := 120], 2), MakeVec1(t->a)), Vec(DefaultVecMap()[0 := 58][1 := 58], 2)), t->m), Vec(DefaultVecMap()[0 := 58][1 := 58], 2)), t->s))); -axiom (forall t: $TypeParamInfo :: {$TypeName(t)} $IsPrefix'vec'u8''($TypeName(t), Vec(DefaultVecMap()[0 := 48][1 := 120], 2)) ==> t is $TypeParamVector); - - -// Given Types for Type Parameters - -type #0; -function {:inline} $IsEqual'#0'(x1: #0, x2: #0): bool { x1 == x2 } -function {:inline} $IsValid'#0'(x: #0): bool { true } -var #0_info: $TypeParamInfo; -var #0_$memory: $Memory #0; - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'bool'(b1), $1_from_bcs_deserializable'bool'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'u8'(b1), $1_from_bcs_deserializable'u8'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'u64'(b1), $1_from_bcs_deserializable'u64'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'u256'(b1), $1_from_bcs_deserializable'u256'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance
-axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'address'(b1), $1_from_bcs_deserializable'address'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'signer'(b1), $1_from_bcs_deserializable'signer'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance > -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'vec'u8''(b1), $1_from_bcs_deserializable'vec'u8''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance > -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'vec'address''(b1), $1_from_bcs_deserializable'vec'address''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance > -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'vec'#0''(b1), $1_from_bcs_deserializable'vec'#0''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::option::Option
> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_option_Option'address''(b1), $1_from_bcs_deserializable'$1_option_Option'address''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::features::Features> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_features_Features'(b1), $1_from_bcs_deserializable'$1_features_Features'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::type_info::TypeInfo> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_type_info_TypeInfo'(b1), $1_from_bcs_deserializable'$1_type_info_TypeInfo'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::table::Table, 0x1::timelock::TimelockTransaction>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b1), $1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::chain_status::GenesisEndMarker> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(b1), $1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timestamp::CurrentTimeMicroseconds> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(b1), $1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::permissioned_signer::GrantedPermissionHandles> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(b1), $1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::guid::GUID> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_guid_GUID'(b1), $1_from_bcs_deserializable'$1_guid_GUID'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::guid::ID> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_guid_ID'(b1), $1_from_bcs_deserializable'$1_guid_ID'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::event::EventHandle<0x1::account::CoinRegisterEvent>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b1), $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::event::EventHandle<0x1::account::KeyRotationEvent>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(b1), $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::event::EventHandle<0x1::reconfiguration::NewEpochEvent>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b1), $1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::Account> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_Account'(b1), $1_from_bcs_deserializable'$1_account_Account'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::CapabilityOffer<0x1::account::RotationCapability>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(b1), $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::CapabilityOffer<0x1::account::SignerCapability>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(b1), $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::account::SignerCapability> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_account_SignerCapability'(b1), $1_from_bcs_deserializable'$1_account_SignerCapability'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::reconfiguration::Configuration> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_reconfiguration_Configuration'(b1), $1_from_bcs_deserializable'$1_reconfiguration_Configuration'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::CreateTransaction> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_CreateTransaction'(b1), $1_from_bcs_deserializable'$1_timelock_CreateTransaction'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::AddCreators> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_AddCreators'(b1), $1_from_bcs_deserializable'$1_timelock_AddCreators'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::AddExecutors> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_AddExecutors'(b1), $1_from_bcs_deserializable'$1_timelock_AddExecutors'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::CancelTransaction> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_CancelTransaction'(b1), $1_from_bcs_deserializable'$1_timelock_CancelTransaction'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::RemoveCreators> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_RemoveCreators'(b1), $1_from_bcs_deserializable'$1_timelock_RemoveCreators'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::RemoveExecutors> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(b1), $1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::TimelockAccount> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_TimelockAccount'(b1), $1_from_bcs_deserializable'$1_timelock_TimelockAccount'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::TimelockTransaction> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(b1), $1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <0x1::timelock::UpdateMinNumSecondsExecute> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(b1), $1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:18:9+124, instance <#0> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserializable'#0'(b1), $1_from_bcs_deserializable'#0'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'bool'($1_from_bcs_deserialize'bool'(b1), $1_from_bcs_deserialize'bool'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'u8'($1_from_bcs_deserialize'u8'(b1), $1_from_bcs_deserialize'u8'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'u64'($1_from_bcs_deserialize'u64'(b1), $1_from_bcs_deserialize'u64'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'u256'($1_from_bcs_deserialize'u256'(b1), $1_from_bcs_deserialize'u256'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance
-axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'address'($1_from_bcs_deserialize'address'(b1), $1_from_bcs_deserialize'address'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'signer'($1_from_bcs_deserialize'signer'(b1), $1_from_bcs_deserialize'signer'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance > -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'vec'u8''($1_from_bcs_deserialize'vec'u8''(b1), $1_from_bcs_deserialize'vec'u8''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance > -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'vec'address''($1_from_bcs_deserialize'vec'address''(b1), $1_from_bcs_deserialize'vec'address''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance > -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'vec'#0''($1_from_bcs_deserialize'vec'#0''(b1), $1_from_bcs_deserialize'vec'#0''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::option::Option
> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_option_Option'address''($1_from_bcs_deserialize'$1_option_Option'address''(b1), $1_from_bcs_deserialize'$1_option_Option'address''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::features::Features> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_features_Features'($1_from_bcs_deserialize'$1_features_Features'(b1), $1_from_bcs_deserialize'$1_features_Features'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::type_info::TypeInfo> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_type_info_TypeInfo'($1_from_bcs_deserialize'$1_type_info_TypeInfo'(b1), $1_from_bcs_deserialize'$1_type_info_TypeInfo'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::table::Table, 0x1::timelock::TimelockTransaction>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''($1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b1), $1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::chain_status::GenesisEndMarker> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_chain_status_GenesisEndMarker'($1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(b1), $1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timestamp::CurrentTimeMicroseconds> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timestamp_CurrentTimeMicroseconds'($1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(b1), $1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::permissioned_signer::GrantedPermissionHandles> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_permissioned_signer_GrantedPermissionHandles'($1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(b1), $1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::guid::GUID> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_guid_GUID'($1_from_bcs_deserialize'$1_guid_GUID'(b1), $1_from_bcs_deserialize'$1_guid_GUID'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::guid::ID> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_guid_ID'($1_from_bcs_deserialize'$1_guid_ID'(b1), $1_from_bcs_deserialize'$1_guid_ID'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::event::EventHandle<0x1::account::CoinRegisterEvent>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_event_EventHandle'$1_account_CoinRegisterEvent''($1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b1), $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::event::EventHandle<0x1::account::KeyRotationEvent>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_event_EventHandle'$1_account_KeyRotationEvent''($1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(b1), $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::event::EventHandle<0x1::reconfiguration::NewEpochEvent>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''($1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b1), $1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::Account> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_Account'($1_from_bcs_deserialize'$1_account_Account'(b1), $1_from_bcs_deserialize'$1_account_Account'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::CapabilityOffer<0x1::account::RotationCapability>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_CapabilityOffer'$1_account_RotationCapability''($1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(b1), $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::CapabilityOffer<0x1::account::SignerCapability>> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_CapabilityOffer'$1_account_SignerCapability''($1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(b1), $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::account::SignerCapability> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_account_SignerCapability'($1_from_bcs_deserialize'$1_account_SignerCapability'(b1), $1_from_bcs_deserialize'$1_account_SignerCapability'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::reconfiguration::Configuration> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_reconfiguration_Configuration'($1_from_bcs_deserialize'$1_reconfiguration_Configuration'(b1), $1_from_bcs_deserialize'$1_reconfiguration_Configuration'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::CreateTransaction> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_CreateTransaction'($1_from_bcs_deserialize'$1_timelock_CreateTransaction'(b1), $1_from_bcs_deserialize'$1_timelock_CreateTransaction'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::AddCreators> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_AddCreators'($1_from_bcs_deserialize'$1_timelock_AddCreators'(b1), $1_from_bcs_deserialize'$1_timelock_AddCreators'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::AddExecutors> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_AddExecutors'($1_from_bcs_deserialize'$1_timelock_AddExecutors'(b1), $1_from_bcs_deserialize'$1_timelock_AddExecutors'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::CancelTransaction> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_CancelTransaction'($1_from_bcs_deserialize'$1_timelock_CancelTransaction'(b1), $1_from_bcs_deserialize'$1_timelock_CancelTransaction'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::RemoveCreators> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_RemoveCreators'($1_from_bcs_deserialize'$1_timelock_RemoveCreators'(b1), $1_from_bcs_deserialize'$1_timelock_RemoveCreators'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::RemoveExecutors> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_RemoveExecutors'($1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(b1), $1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::TimelockAccount> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_TimelockAccount'($1_from_bcs_deserialize'$1_timelock_TimelockAccount'(b1), $1_from_bcs_deserialize'$1_timelock_TimelockAccount'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::TimelockTransaction> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_TimelockTransaction'($1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(b1), $1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <0x1::timelock::UpdateMinNumSecondsExecute> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'$1_timelock_UpdateMinNumSecondsExecute'($1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(b1), $1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:21:9+118, instance <#0> -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''(b1, b2) ==> $IsEqual'#0'($1_from_bcs_deserialize'#0'(b1), $1_from_bcs_deserialize'#0'(b2))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/permissioned_signer.spec.move:5:9+288 -axiom (forall a: $1_permissioned_signer_GrantedPermissionHandles :: $IsValid'$1_permissioned_signer_GrantedPermissionHandles'(a) ==> ((var $range_0 := $Range(0, LenVec(a->$active_handles)); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var i := $i_1; -((var $range_2 := $Range(0, LenVec(a->$active_handles)); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var j := $i_3; -((!$IsEqual'num'(i, j) ==> !$IsEqual'address'(ReadVec(a->$active_handles, i), ReadVec(a->$active_handles, j))))))))))))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:8:9+113 -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_keccak256(b1), $1_aptos_hash_spec_keccak256(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:13:9+129 -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_sha2_512_internal(b1), $1_aptos_hash_spec_sha2_512_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:18:9+129 -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_sha3_512_internal(b1), $1_aptos_hash_spec_sha3_512_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:23:9+131 -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_ripemd160_internal(b1), $1_aptos_hash_spec_ripemd160_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); - -// axiom at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:28:9+135 -axiom (forall b1: Vec (int), b2: Vec (int) :: $IsValid'vec'u8''(b1) ==> $IsValid'vec'u8''(b2) ==> (($IsEqual'vec'u8''($1_aptos_hash_spec_blake2b_256_internal(b1), $1_aptos_hash_spec_blake2b_256_internal(b2)) ==> $IsEqual'vec'u8''(b1, b2)))); - -// struct option::Option
at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/option.move:7:5+81 -datatype $1_option_Option'address' { - $1_option_Option'address'($vec: Vec (int)) -} -function {:inline} $Update'$1_option_Option'address''_vec(s: $1_option_Option'address', x: Vec (int)): $1_option_Option'address' { - $1_option_Option'address'(x) -} -function $IsValid'$1_option_Option'address''(s: $1_option_Option'address'): bool { - $IsValid'vec'address''(s->$vec) -} -function {:inline} $IsEqual'$1_option_Option'address''(s1: $1_option_Option'address', s2: $1_option_Option'address'): bool { - $IsEqual'vec'address''(s1->$vec, s2->$vec)} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:26:5+77 -function {:inline} $1_signer_$address_of(s: $signer): int { - $1_signer_$borrow_address(s) -} - -// fun signer::address_of [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:26:5+77 -procedure {:inline 1} $1_signer_address_of(_$t0: $signer) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: int; - var $t0: $signer; - var $temp_0'address': int; - var $temp_0'signer': $signer; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[s]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:26:5+1 - assume {:print "$at(16,794,795)"} true; - assume {:print "$track_local(4,0,0):", $t0} $t0 == $t0; - - // $t1 := signer::borrow_address($t0) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:27:10+17 - assume {:print "$at(16,848,865)"} true; - call $t1 := $1_signer_borrow_address($t0); - if ($abort_flag) { - assume {:print "$at(16,848,865)"} true; - $t2 := $abort_code; - assume {:print "$track_abort(4,0):", $t2} $t2 == $t2; - goto L2; - } - - // trace_return[0]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:27:9+18 - assume {:print "$track_return(4,0,0):", $t1} $t1 == $t1; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 - assume {:print "$at(16,870,871)"} true; -L1: - - // return $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 - assume {:print "$at(16,870,871)"} true; - $ret0 := $t1; - return; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 -L2: - - // abort($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/signer.move:28:5+1 - assume {:print "$at(16,870,871)"} true; - $abort_code := $t2; - $abort_flag := true; - return; - -} - -// fun error::already_exists [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:3+71 -procedure {:inline 1} $1_error_already_exists(_$t0: int) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: int; - var $t3: int; - var $t0: int; - var $temp_0'u64': int; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:3+1 - assume {:print "$at(11,3585,3586)"} true; - assume {:print "$track_local(5,1,0):", $t0} $t0 == $t0; - - // $t1 := 8 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:54+14 - $t1 := 8; - assume $IsValid'u64'($t1); - - // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 - assume {:print "$at(11,2844,2873)"} true; - assume ($t2 == $shlU64($t1, 16)); - - // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 - assume {:print "$at(11,3626,3654)"} true; - - // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 - assume $IsValid'u64'($t3); - - // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 - assume $IsEqual'u64'($t3, $t1); - - // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:44+28 - assume {:print "$track_return(5,1,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:73+1 -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:83:73+1 - assume {:print "$at(11,3655,3656)"} true; - $ret0 := $t3; - return; - -} - -// fun error::invalid_argument [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:3+76 -procedure {:inline 1} $1_error_invalid_argument(_$t0: int) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: int; - var $t3: int; - var $t0: int; - var $temp_0'u64': int; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:3+1 - assume {:print "$at(11,3082,3083)"} true; - assume {:print "$track_local(5,4,0):", $t0} $t0 == $t0; - - // $t1 := 1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:57+16 - $t1 := 1; - assume $IsValid'u64'($t1); - - // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 - assume {:print "$at(11,2844,2873)"} true; - assume ($t2 == $shlU64($t1, 16)); - - // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 - assume {:print "$at(11,3126,3156)"} true; - - // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 - assume $IsValid'u64'($t3); - - // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 - assume $IsEqual'u64'($t3, $t1); - - // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:47+30 - assume {:print "$track_return(5,4,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:78+1 -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:76:78+1 - assume {:print "$at(11,3157,3158)"} true; - $ret0 := $t3; - return; - -} - -// fun error::invalid_state [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:3+70 -procedure {:inline 1} $1_error_invalid_state(_$t0: int) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: int; - var $t3: int; - var $t0: int; - var $temp_0'u64': int; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:3+1 - assume {:print "$at(11,3232,3233)"} true; - assume {:print "$track_local(5,5,0):", $t0} $t0 == $t0; - - // $t1 := 3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:54+13 - $t1 := 3; - assume $IsValid'u64'($t1); - - // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 - assume {:print "$at(11,2844,2873)"} true; - assume ($t2 == $shlU64($t1, 16)); - - // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 - assume {:print "$at(11,3273,3300)"} true; - - // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 - assume $IsValid'u64'($t3); - - // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 - assume $IsEqual'u64'($t3, $t1); - - // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:44+27 - assume {:print "$track_return(5,5,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:72+1 -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:78:72+1 - assume {:print "$at(11,3301,3302)"} true; - $ret0 := $t3; - return; - -} - -// fun error::not_found [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:3+61 -procedure {:inline 1} $1_error_not_found(_$t0: int) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: int; - var $t3: int; - var $t0: int; - var $temp_0'u64': int; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:3+1 - assume {:print "$at(11,3461,3462)"} true; - assume {:print "$track_local(5,6,0):", $t0} $t0 == $t0; - - // $t1 := 6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:49+9 - $t1 := 6; - assume $IsValid'u64'($t1); - - // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 - assume {:print "$at(11,2844,2873)"} true; - assume ($t2 == $shlU64($t1, 16)); - - // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 - assume {:print "$at(11,3497,3520)"} true; - - // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 - assume $IsValid'u64'($t3); - - // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 - assume $IsEqual'u64'($t3, $t1); - - // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:39+23 - assume {:print "$track_return(5,6,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:63+1 -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:81:63+1 - assume {:print "$at(11,3521,3522)"} true; - $ret0 := $t3; - return; - -} - -// fun error::permission_denied [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:3+77 -procedure {:inline 1} $1_error_permission_denied(_$t0: int) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: int; - var $t3: int; - var $t0: int; - var $temp_0'u64': int; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[r]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:3+1 - assume {:print "$at(11,3381,3382)"} true; - assume {:print "$track_local(5,9,0):", $t0} $t0 == $t0; - - // $t1 := 5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:57+17 - $t1 := 5; - assume $IsValid'u64'($t1); - - // assume Identical($t2, Shl($t1, 16)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:69:5+29 - assume {:print "$at(11,2844,2873)"} true; - assume ($t2 == $shlU64($t1, 16)); - - // $t3 := opaque begin: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 - assume {:print "$at(11,3425,3456)"} true; - - // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 - assume $IsValid'u64'($t3); - - // assume Eq($t3, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 - assume $IsEqual'u64'($t3, $t1); - - // $t3 := opaque end: error::canonical($t1, $t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:47+31 - assume {:print "$track_return(5,9,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:79+1 -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/error.move:80:79+1 - assume {:print "$at(11,3457,3458)"} true; - $ret0 := $t3; - return; - -} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/configs/features.spec.move:61:10+40 -function $1_features_spec_is_enabled(feature: int): bool; -axiom (forall feature: int :: -(var $$res := $1_features_spec_is_enabled(feature); -$IsValid'bool'($$res))); - -// struct features::Features at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/../move-stdlib/sources/configs/features.move:800:5+61 -datatype $1_features_Features { - $1_features_Features($features: Vec (bv8)) -} -function {:inline} $Update'$1_features_Features'_features(s: $1_features_Features, x: Vec (bv8)): $1_features_Features { - $1_features_Features(x) -} -function $IsValid'$1_features_Features'(s: $1_features_Features): bool { - $IsValid'vec'bv8''(s->$features) -} -function {:inline} $IsEqual'$1_features_Features'(s1: $1_features_Features, s2: $1_features_Features): bool { - $IsEqual'vec'bv8''(s1->$features, s2->$features)} -var $1_features_Features_$memory: $Memory $1_features_Features; - -// struct type_info::TypeInfo at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/type_info.move:19:5+145 -datatype $1_type_info_TypeInfo { - $1_type_info_TypeInfo($account_address: int, $module_name: Vec (int), $struct_name: Vec (int)) -} -function {:inline} $Update'$1_type_info_TypeInfo'_account_address(s: $1_type_info_TypeInfo, x: int): $1_type_info_TypeInfo { - $1_type_info_TypeInfo(x, s->$module_name, s->$struct_name) -} -function {:inline} $Update'$1_type_info_TypeInfo'_module_name(s: $1_type_info_TypeInfo, x: Vec (int)): $1_type_info_TypeInfo { - $1_type_info_TypeInfo(s->$account_address, x, s->$struct_name) -} -function {:inline} $Update'$1_type_info_TypeInfo'_struct_name(s: $1_type_info_TypeInfo, x: Vec (int)): $1_type_info_TypeInfo { - $1_type_info_TypeInfo(s->$account_address, s->$module_name, x) -} -function $IsValid'$1_type_info_TypeInfo'(s: $1_type_info_TypeInfo): bool { - $IsValid'address'(s->$account_address) - && $IsValid'vec'u8''(s->$module_name) - && $IsValid'vec'u8''(s->$struct_name) -} -function {:inline} $IsEqual'$1_type_info_TypeInfo'(s1: $1_type_info_TypeInfo, s2: $1_type_info_TypeInfo): bool { - $IsEqual'address'(s1->$account_address, s2->$account_address) - && $IsEqual'vec'u8''(s1->$module_name, s2->$module_name) - && $IsEqual'vec'u8''(s1->$struct_name, s2->$struct_name)} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'bool'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'bool'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'u8'(bytes: Vec (int)): int; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'u8'(bytes); -$IsValid'u8'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'u64'(bytes: Vec (int)): int; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'u64'(bytes); -$IsValid'u64'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'u256'(bytes: Vec (int)): int; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'u256'(bytes); -$IsValid'u256'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'address'(bytes: Vec (int)): int; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'address'(bytes); -$IsValid'address'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'signer'(bytes: Vec (int)): $signer; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'signer'(bytes); -$IsValid'signer'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'vec'u8''(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'vec'u8''(bytes); -$IsValid'vec'u8''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'vec'address''(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'vec'address''(bytes); -$IsValid'vec'address''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'vec'#0''(bytes: Vec (int)): Vec (#0); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'vec'#0''(bytes); -$IsValid'vec'#0''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_option_Option'address''(bytes: Vec (int)): $1_option_Option'address'; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_option_Option'address''(bytes); -$IsValid'$1_option_Option'address''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_features_Features'(bytes: Vec (int)): $1_features_Features; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_features_Features'(bytes); -$IsValid'$1_features_Features'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_type_info_TypeInfo'(bytes: Vec (int)): $1_type_info_TypeInfo; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_type_info_TypeInfo'(bytes); -$IsValid'$1_type_info_TypeInfo'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes: Vec (int)): Table int ($1_timelock_TimelockTransaction); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes); -$IsValid'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(bytes: Vec (int)): $1_chain_status_GenesisEndMarker; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_chain_status_GenesisEndMarker'(bytes); -$IsValid'$1_chain_status_GenesisEndMarker'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(bytes: Vec (int)): $1_timestamp_CurrentTimeMicroseconds; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timestamp_CurrentTimeMicroseconds'(bytes); -$IsValid'$1_timestamp_CurrentTimeMicroseconds'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(bytes: Vec (int)): $1_permissioned_signer_GrantedPermissionHandles; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_permissioned_signer_GrantedPermissionHandles'(bytes); -$IsValid'$1_permissioned_signer_GrantedPermissionHandles'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_guid_GUID'(bytes: Vec (int)): $1_guid_GUID; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_guid_GUID'(bytes); -$IsValid'$1_guid_GUID'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_guid_ID'(bytes: Vec (int)): $1_guid_ID; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_guid_ID'(bytes); -$IsValid'$1_guid_ID'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes: Vec (int)): $1_event_EventHandle'$1_account_CoinRegisterEvent'; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes); -$IsValid'$1_event_EventHandle'$1_account_CoinRegisterEvent''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes: Vec (int)): $1_event_EventHandle'$1_account_KeyRotationEvent'; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes); -$IsValid'$1_event_EventHandle'$1_account_KeyRotationEvent''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes: Vec (int)): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes); -$IsValid'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_account_Account'(bytes: Vec (int)): $1_account_Account; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_account_Account'(bytes); -$IsValid'$1_account_Account'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes: Vec (int)): $1_account_CapabilityOffer'$1_account_RotationCapability'; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes); -$IsValid'$1_account_CapabilityOffer'$1_account_RotationCapability''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes: Vec (int)): $1_account_CapabilityOffer'$1_account_SignerCapability'; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes); -$IsValid'$1_account_CapabilityOffer'$1_account_SignerCapability''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_account_SignerCapability'(bytes: Vec (int)): $1_account_SignerCapability; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_account_SignerCapability'(bytes); -$IsValid'$1_account_SignerCapability'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_reconfiguration_Configuration'(bytes: Vec (int)): $1_reconfiguration_Configuration; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_reconfiguration_Configuration'(bytes); -$IsValid'$1_reconfiguration_Configuration'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_CreateTransaction'(bytes: Vec (int)): $1_timelock_CreateTransaction; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_CreateTransaction'(bytes); -$IsValid'$1_timelock_CreateTransaction'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_AddCreators'(bytes: Vec (int)): $1_timelock_AddCreators; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_AddCreators'(bytes); -$IsValid'$1_timelock_AddCreators'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_AddExecutors'(bytes: Vec (int)): $1_timelock_AddExecutors; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_AddExecutors'(bytes); -$IsValid'$1_timelock_AddExecutors'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_CancelTransaction'(bytes: Vec (int)): $1_timelock_CancelTransaction; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_CancelTransaction'(bytes); -$IsValid'$1_timelock_CancelTransaction'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_RemoveCreators'(bytes: Vec (int)): $1_timelock_RemoveCreators; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_RemoveCreators'(bytes); -$IsValid'$1_timelock_RemoveCreators'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(bytes: Vec (int)): $1_timelock_RemoveExecutors; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_RemoveExecutors'(bytes); -$IsValid'$1_timelock_RemoveExecutors'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_TimelockAccount'(bytes: Vec (int)): $1_timelock_TimelockAccount; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_TimelockAccount'(bytes); -$IsValid'$1_timelock_TimelockAccount'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(bytes: Vec (int)): $1_timelock_TimelockTransaction; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_TimelockTransaction'(bytes); -$IsValid'$1_timelock_TimelockTransaction'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(bytes: Vec (int)): $1_timelock_UpdateMinNumSecondsExecute; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'$1_timelock_UpdateMinNumSecondsExecute'(bytes); -$IsValid'$1_timelock_UpdateMinNumSecondsExecute'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:7:9+41 -function $1_from_bcs_deserialize'#0'(bytes: Vec (int)): #0; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserialize'#0'(bytes); -$IsValid'#0'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'bool'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'bool'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'u8'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'u8'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'u64'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'u64'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'u256'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'u256'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'address'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'address'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'signer'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'signer'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'vec'u8''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'vec'u8''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'vec'address''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'vec'address''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'vec'#0''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'vec'#0''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_option_Option'address''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_option_Option'address''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_features_Features'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_features_Features'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_type_info_TypeInfo'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_type_info_TypeInfo'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_chain_status_GenesisEndMarker'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timestamp_CurrentTimeMicroseconds'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_permissioned_signer_GrantedPermissionHandles'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_guid_GUID'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_guid_GUID'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_guid_ID'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_guid_ID'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_CoinRegisterEvent''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_event_EventHandle'$1_account_KeyRotationEvent''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_account_Account'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_account_Account'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_RotationCapability''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_account_CapabilityOffer'$1_account_SignerCapability''(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_account_SignerCapability'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_account_SignerCapability'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_reconfiguration_Configuration'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_reconfiguration_Configuration'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_CreateTransaction'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_CreateTransaction'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_AddCreators'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_AddCreators'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_AddExecutors'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_AddExecutors'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_CancelTransaction'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_CancelTransaction'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_RemoveCreators'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_RemoveCreators'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_RemoveExecutors'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_TimelockAccount'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_TimelockAccount'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_TimelockTransaction'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'$1_timelock_UpdateMinNumSecondsExecute'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/from_bcs.spec.move:11:9+47 -function $1_from_bcs_deserializable'#0'(bytes: Vec (int)): bool; -axiom (forall bytes: Vec (int) :: -(var $$res := $1_from_bcs_deserializable'#0'(bytes); -$IsValid'bool'($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/chain_status.move:35:5+90 -function {:inline} $1_chain_status_$is_operating($1_chain_status_GenesisEndMarker_$memory: $Memory $1_chain_status_GenesisEndMarker): bool { - $ResourceExists($1_chain_status_GenesisEndMarker_$memory, 1) -} - -// struct chain_status::GenesisEndMarker at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/chain_status.move:12:5+34 -datatype $1_chain_status_GenesisEndMarker { - $1_chain_status_GenesisEndMarker($dummy_field: bool) -} -function {:inline} $Update'$1_chain_status_GenesisEndMarker'_dummy_field(s: $1_chain_status_GenesisEndMarker, x: bool): $1_chain_status_GenesisEndMarker { - $1_chain_status_GenesisEndMarker(x) -} -function $IsValid'$1_chain_status_GenesisEndMarker'(s: $1_chain_status_GenesisEndMarker): bool { - $IsValid'bool'(s->$dummy_field) -} -function {:inline} $IsEqual'$1_chain_status_GenesisEndMarker'(s1: $1_chain_status_GenesisEndMarker, s2: $1_chain_status_GenesisEndMarker): bool { - s1 == s2 -} -var $1_chain_status_GenesisEndMarker_$memory: $Memory $1_chain_status_GenesisEndMarker; - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.spec.move:57:10+111 -function {:inline} $1_timestamp_spec_now_microseconds($1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds): int { - $ResourceValue($1_timestamp_CurrentTimeMicroseconds_$memory, 1)->$microseconds -} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:61:5+153 -function {:inline} $1_timestamp_$now_microseconds($1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds): int { - $ResourceValue($1_timestamp_CurrentTimeMicroseconds_$memory, 1)->$microseconds -} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:67:5+123 -function {:inline} $1_timestamp_$now_seconds($1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds): int { - ($1_timestamp_$now_microseconds($1_timestamp_CurrentTimeMicroseconds_$memory) div 1000000) -} - -// struct timestamp::CurrentTimeMicroseconds at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:12:5+73 -datatype $1_timestamp_CurrentTimeMicroseconds { - $1_timestamp_CurrentTimeMicroseconds($microseconds: int) -} -function {:inline} $Update'$1_timestamp_CurrentTimeMicroseconds'_microseconds(s: $1_timestamp_CurrentTimeMicroseconds, x: int): $1_timestamp_CurrentTimeMicroseconds { - $1_timestamp_CurrentTimeMicroseconds(x) -} -function $IsValid'$1_timestamp_CurrentTimeMicroseconds'(s: $1_timestamp_CurrentTimeMicroseconds): bool { - $IsValid'u64'(s->$microseconds) -} -function {:inline} $IsEqual'$1_timestamp_CurrentTimeMicroseconds'(s1: $1_timestamp_CurrentTimeMicroseconds, s2: $1_timestamp_CurrentTimeMicroseconds): bool { - s1 == s2 -} -var $1_timestamp_CurrentTimeMicroseconds_$memory: $Memory $1_timestamp_CurrentTimeMicroseconds; - -// fun timestamp::now_microseconds [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:61:5+153 -procedure {:inline 1} $1_timestamp_now_microseconds() returns ($ret0: int) -{ - // declare local variables - var $t0: int; - var $t1: $1_timestamp_CurrentTimeMicroseconds; - var $t2: int; - var $t3: int; - var $temp_0'u64': int; - - // bytecode translation starts here - // $t0 := 0x1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:48+16 - assume {:print "$at(220,2511,2527)"} true; - $t0 := 1; - assume $IsValid'address'($t0); - - // $t1 := get_global<0x1::timestamp::CurrentTimeMicroseconds>($t0) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:9+56 - if (!$ResourceExists($1_timestamp_CurrentTimeMicroseconds_$memory, $t0)) { - call $ExecFailureAbort(); - } else { - $t1 := $ResourceValue($1_timestamp_CurrentTimeMicroseconds_$memory, $t0); - } - if ($abort_flag) { - assume {:print "$at(220,2472,2528)"} true; - $t2 := $abort_code; - assume {:print "$track_abort(22,0):", $t2} $t2 == $t2; - goto L2; - } - - // $t3 := get_field<0x1::timestamp::CurrentTimeMicroseconds>.microseconds($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:9+69 - $t3 := $t1->$microseconds; - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:62:9+69 - assume {:print "$track_return(22,0,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 - assume {:print "$at(220,2546,2547)"} true; -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 - assume {:print "$at(220,2546,2547)"} true; - $ret0 := $t3; - return; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 -L2: - - // abort($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:63:5+1 - assume {:print "$at(220,2546,2547)"} true; - $abort_code := $t2; - $abort_flag := true; - return; - -} - -// fun timestamp::now_seconds [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:67:5+123 -procedure {:inline 1} $1_timestamp_now_seconds() returns ($ret0: int) -{ - // declare local variables - var $t0: int; - var $t1: int; - var $t2: int; - var $t3: int; - var $temp_0'u64': int; - - // bytecode translation starts here - // $t0 := timestamp::now_microseconds() on_abort goto L2 with $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:9+18 - assume {:print "$at(220,2680,2698)"} true; - call $t0 := $1_timestamp_now_microseconds(); - if ($abort_flag) { - assume {:print "$at(220,2680,2698)"} true; - $t1 := $abort_code; - assume {:print "$track_abort(22,1):", $t1} $t1 == $t1; - goto L2; - } - - // $t2 := 1000000 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:30+23 - $t2 := 1000000; - assume $IsValid'u64'($t2); - - // $t3 := /($t0, $t2) on_abort goto L2 with $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:9+44 - call $t3 := $Div($t0, $t2); - if ($abort_flag) { - assume {:print "$at(220,2680,2724)"} true; - $t1 := $abort_code; - assume {:print "$track_abort(22,1):", $t1} $t1 == $t1; - goto L2; - } - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:68:9+44 - assume {:print "$track_return(22,1,0):", $t3} $t3 == $t3; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 - assume {:print "$at(220,2729,2730)"} true; -L1: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 - assume {:print "$at(220,2729,2730)"} true; - $ret0 := $t3; - return; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 -L2: - - // abort($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timestamp.move:69:5+1 - assume {:print "$at(220,2729,2730)"} true; - $abort_code := $t1; - $abort_flag := true; - return; - -} - -// struct permissioned_signer::GrantedPermissionHandles at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/permissioned_signer.move:64:5+188 -datatype $1_permissioned_signer_GrantedPermissionHandles { - $1_permissioned_signer_GrantedPermissionHandles($active_handles: Vec (int)) -} -function {:inline} $Update'$1_permissioned_signer_GrantedPermissionHandles'_active_handles(s: $1_permissioned_signer_GrantedPermissionHandles, x: Vec (int)): $1_permissioned_signer_GrantedPermissionHandles { - $1_permissioned_signer_GrantedPermissionHandles(x) -} -function $IsValid'$1_permissioned_signer_GrantedPermissionHandles'(s: $1_permissioned_signer_GrantedPermissionHandles): bool { - $IsValid'vec'address''(s->$active_handles) -} -function {:inline} $IsEqual'$1_permissioned_signer_GrantedPermissionHandles'(s1: $1_permissioned_signer_GrantedPermissionHandles, s2: $1_permissioned_signer_GrantedPermissionHandles): bool { - $IsEqual'vec'address''(s1->$active_handles, s2->$active_handles)} -var $1_permissioned_signer_GrantedPermissionHandles_$memory: $Memory $1_permissioned_signer_GrantedPermissionHandles; - -// struct guid::GUID at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/guid.move:7:5+50 -datatype $1_guid_GUID { - $1_guid_GUID($id: $1_guid_ID) -} -function {:inline} $Update'$1_guid_GUID'_id(s: $1_guid_GUID, x: $1_guid_ID): $1_guid_GUID { - $1_guid_GUID(x) -} -function $IsValid'$1_guid_GUID'(s: $1_guid_GUID): bool { - $IsValid'$1_guid_ID'(s->$id) -} -function {:inline} $IsEqual'$1_guid_GUID'(s1: $1_guid_GUID, s2: $1_guid_GUID): bool { - s1 == s2 -} - -// struct guid::ID at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/guid.move:12:5+209 -datatype $1_guid_ID { - $1_guid_ID($creation_num: int, $addr: int) -} -function {:inline} $Update'$1_guid_ID'_creation_num(s: $1_guid_ID, x: int): $1_guid_ID { - $1_guid_ID(x, s->$addr) -} -function {:inline} $Update'$1_guid_ID'_addr(s: $1_guid_ID, x: int): $1_guid_ID { - $1_guid_ID(s->$creation_num, x) -} -function $IsValid'$1_guid_ID'(s: $1_guid_ID): bool { - $IsValid'u64'(s->$creation_num) - && $IsValid'address'(s->$addr) -} -function {:inline} $IsEqual'$1_guid_ID'(s1: $1_guid_ID, s2: $1_guid_ID): bool { - s1 == s2 -} - -// struct event::EventHandle<0x1::account::CoinRegisterEvent> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/event.move:37:5+224 -datatype $1_event_EventHandle'$1_account_CoinRegisterEvent' { - $1_event_EventHandle'$1_account_CoinRegisterEvent'($counter: int, $guid: $1_guid_GUID) -} -function {:inline} $Update'$1_event_EventHandle'$1_account_CoinRegisterEvent''_counter(s: $1_event_EventHandle'$1_account_CoinRegisterEvent', x: int): $1_event_EventHandle'$1_account_CoinRegisterEvent' { - $1_event_EventHandle'$1_account_CoinRegisterEvent'(x, s->$guid) -} -function {:inline} $Update'$1_event_EventHandle'$1_account_CoinRegisterEvent''_guid(s: $1_event_EventHandle'$1_account_CoinRegisterEvent', x: $1_guid_GUID): $1_event_EventHandle'$1_account_CoinRegisterEvent' { - $1_event_EventHandle'$1_account_CoinRegisterEvent'(s->$counter, x) -} -function $IsValid'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s: $1_event_EventHandle'$1_account_CoinRegisterEvent'): bool { - $IsValid'u64'(s->$counter) - && $IsValid'$1_guid_GUID'(s->$guid) -} -function {:inline} $IsEqual'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s1: $1_event_EventHandle'$1_account_CoinRegisterEvent', s2: $1_event_EventHandle'$1_account_CoinRegisterEvent'): bool { - s1 == s2 -} - -// struct event::EventHandle<0x1::account::KeyRotationEvent> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/event.move:37:5+224 -datatype $1_event_EventHandle'$1_account_KeyRotationEvent' { - $1_event_EventHandle'$1_account_KeyRotationEvent'($counter: int, $guid: $1_guid_GUID) -} -function {:inline} $Update'$1_event_EventHandle'$1_account_KeyRotationEvent''_counter(s: $1_event_EventHandle'$1_account_KeyRotationEvent', x: int): $1_event_EventHandle'$1_account_KeyRotationEvent' { - $1_event_EventHandle'$1_account_KeyRotationEvent'(x, s->$guid) -} -function {:inline} $Update'$1_event_EventHandle'$1_account_KeyRotationEvent''_guid(s: $1_event_EventHandle'$1_account_KeyRotationEvent', x: $1_guid_GUID): $1_event_EventHandle'$1_account_KeyRotationEvent' { - $1_event_EventHandle'$1_account_KeyRotationEvent'(s->$counter, x) -} -function $IsValid'$1_event_EventHandle'$1_account_KeyRotationEvent''(s: $1_event_EventHandle'$1_account_KeyRotationEvent'): bool { - $IsValid'u64'(s->$counter) - && $IsValid'$1_guid_GUID'(s->$guid) -} -function {:inline} $IsEqual'$1_event_EventHandle'$1_account_KeyRotationEvent''(s1: $1_event_EventHandle'$1_account_KeyRotationEvent', s2: $1_event_EventHandle'$1_account_KeyRotationEvent'): bool { - s1 == s2 -} - -// struct event::EventHandle<0x1::reconfiguration::NewEpochEvent> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/event.move:37:5+224 -datatype $1_event_EventHandle'$1_reconfiguration_NewEpochEvent' { - $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'($counter: int, $guid: $1_guid_GUID) -} -function {:inline} $Update'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''_counter(s: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent', x: int): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent' { - $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'(x, s->$guid) -} -function {:inline} $Update'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''_guid(s: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent', x: $1_guid_GUID): $1_event_EventHandle'$1_reconfiguration_NewEpochEvent' { - $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'(s->$counter, x) -} -function $IsValid'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(s: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'): bool { - $IsValid'u64'(s->$counter) - && $IsValid'$1_guid_GUID'(s->$guid) -} -function {:inline} $IsEqual'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(s1: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent', s2: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'): bool { - s1 == s2 -} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.spec.move:598:10+77 -function $1_account_spec_create_resource_address(source: int, seed: Vec (int)): int; -axiom (forall source: int, seed: Vec (int) :: -(var $$res := $1_account_spec_create_resource_address(source, seed); -$IsValid'address'($$res))); - -// struct account::Account at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:61:5+401 -datatype $1_account_Account { - $1_account_Account($authentication_key: Vec (int), $sequence_number: int, $guid_creation_num: int, $coin_register_events: $1_event_EventHandle'$1_account_CoinRegisterEvent', $key_rotation_events: $1_event_EventHandle'$1_account_KeyRotationEvent', $rotation_capability_offer: $1_account_CapabilityOffer'$1_account_RotationCapability', $signer_capability_offer: $1_account_CapabilityOffer'$1_account_SignerCapability') -} -function {:inline} $Update'$1_account_Account'_authentication_key(s: $1_account_Account, x: Vec (int)): $1_account_Account { - $1_account_Account(x, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) -} -function {:inline} $Update'$1_account_Account'_sequence_number(s: $1_account_Account, x: int): $1_account_Account { - $1_account_Account(s->$authentication_key, x, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) -} -function {:inline} $Update'$1_account_Account'_guid_creation_num(s: $1_account_Account, x: int): $1_account_Account { - $1_account_Account(s->$authentication_key, s->$sequence_number, x, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) -} -function {:inline} $Update'$1_account_Account'_coin_register_events(s: $1_account_Account, x: $1_event_EventHandle'$1_account_CoinRegisterEvent'): $1_account_Account { - $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, x, s->$key_rotation_events, s->$rotation_capability_offer, s->$signer_capability_offer) -} -function {:inline} $Update'$1_account_Account'_key_rotation_events(s: $1_account_Account, x: $1_event_EventHandle'$1_account_KeyRotationEvent'): $1_account_Account { - $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, x, s->$rotation_capability_offer, s->$signer_capability_offer) -} -function {:inline} $Update'$1_account_Account'_rotation_capability_offer(s: $1_account_Account, x: $1_account_CapabilityOffer'$1_account_RotationCapability'): $1_account_Account { - $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, x, s->$signer_capability_offer) -} -function {:inline} $Update'$1_account_Account'_signer_capability_offer(s: $1_account_Account, x: $1_account_CapabilityOffer'$1_account_SignerCapability'): $1_account_Account { - $1_account_Account(s->$authentication_key, s->$sequence_number, s->$guid_creation_num, s->$coin_register_events, s->$key_rotation_events, s->$rotation_capability_offer, x) -} -function $IsValid'$1_account_Account'(s: $1_account_Account): bool { - $IsValid'vec'u8''(s->$authentication_key) - && $IsValid'u64'(s->$sequence_number) - && $IsValid'u64'(s->$guid_creation_num) - && $IsValid'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s->$coin_register_events) - && $IsValid'$1_event_EventHandle'$1_account_KeyRotationEvent''(s->$key_rotation_events) - && $IsValid'$1_account_CapabilityOffer'$1_account_RotationCapability''(s->$rotation_capability_offer) - && $IsValid'$1_account_CapabilityOffer'$1_account_SignerCapability''(s->$signer_capability_offer) -} -function {:inline} $IsEqual'$1_account_Account'(s1: $1_account_Account, s2: $1_account_Account): bool { - $IsEqual'vec'u8''(s1->$authentication_key, s2->$authentication_key) - && $IsEqual'u64'(s1->$sequence_number, s2->$sequence_number) - && $IsEqual'u64'(s1->$guid_creation_num, s2->$guid_creation_num) - && $IsEqual'$1_event_EventHandle'$1_account_CoinRegisterEvent''(s1->$coin_register_events, s2->$coin_register_events) - && $IsEqual'$1_event_EventHandle'$1_account_KeyRotationEvent''(s1->$key_rotation_events, s2->$key_rotation_events) - && $IsEqual'$1_account_CapabilityOffer'$1_account_RotationCapability''(s1->$rotation_capability_offer, s2->$rotation_capability_offer) - && $IsEqual'$1_account_CapabilityOffer'$1_account_SignerCapability''(s1->$signer_capability_offer, s2->$signer_capability_offer)} -var $1_account_Account_$memory: $Memory $1_account_Account; - -// struct account::CapabilityOffer<0x1::account::RotationCapability> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:86:5+68 -datatype $1_account_CapabilityOffer'$1_account_RotationCapability' { - $1_account_CapabilityOffer'$1_account_RotationCapability'($for: $1_option_Option'address') -} -function {:inline} $Update'$1_account_CapabilityOffer'$1_account_RotationCapability''_for(s: $1_account_CapabilityOffer'$1_account_RotationCapability', x: $1_option_Option'address'): $1_account_CapabilityOffer'$1_account_RotationCapability' { - $1_account_CapabilityOffer'$1_account_RotationCapability'(x) -} -function $IsValid'$1_account_CapabilityOffer'$1_account_RotationCapability''(s: $1_account_CapabilityOffer'$1_account_RotationCapability'): bool { - $IsValid'$1_option_Option'address''(s->$for) -} -function {:inline} $IsEqual'$1_account_CapabilityOffer'$1_account_RotationCapability''(s1: $1_account_CapabilityOffer'$1_account_RotationCapability', s2: $1_account_CapabilityOffer'$1_account_RotationCapability'): bool { - $IsEqual'$1_option_Option'address''(s1->$for, s2->$for)} - -// struct account::CapabilityOffer<0x1::account::SignerCapability> at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:86:5+68 -datatype $1_account_CapabilityOffer'$1_account_SignerCapability' { - $1_account_CapabilityOffer'$1_account_SignerCapability'($for: $1_option_Option'address') -} -function {:inline} $Update'$1_account_CapabilityOffer'$1_account_SignerCapability''_for(s: $1_account_CapabilityOffer'$1_account_SignerCapability', x: $1_option_Option'address'): $1_account_CapabilityOffer'$1_account_SignerCapability' { - $1_account_CapabilityOffer'$1_account_SignerCapability'(x) -} -function $IsValid'$1_account_CapabilityOffer'$1_account_SignerCapability''(s: $1_account_CapabilityOffer'$1_account_SignerCapability'): bool { - $IsValid'$1_option_Option'address''(s->$for) -} -function {:inline} $IsEqual'$1_account_CapabilityOffer'$1_account_SignerCapability''(s1: $1_account_CapabilityOffer'$1_account_SignerCapability', s2: $1_account_CapabilityOffer'$1_account_SignerCapability'): bool { - $IsEqual'$1_option_Option'address''(s1->$for, s2->$for)} - -// struct account::CoinRegisterEvent at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:76:5+77 -datatype $1_account_CoinRegisterEvent { - $1_account_CoinRegisterEvent($type_info: $1_type_info_TypeInfo) -} -function {:inline} $Update'$1_account_CoinRegisterEvent'_type_info(s: $1_account_CoinRegisterEvent, x: $1_type_info_TypeInfo): $1_account_CoinRegisterEvent { - $1_account_CoinRegisterEvent(x) -} -function $IsValid'$1_account_CoinRegisterEvent'(s: $1_account_CoinRegisterEvent): bool { - $IsValid'$1_type_info_TypeInfo'(s->$type_info) -} -function {:inline} $IsEqual'$1_account_CoinRegisterEvent'(s1: $1_account_CoinRegisterEvent, s2: $1_account_CoinRegisterEvent): bool { - $IsEqual'$1_type_info_TypeInfo'(s1->$type_info, s2->$type_info)} - -// struct account::KeyRotationEvent at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:71:5+135 -datatype $1_account_KeyRotationEvent { - $1_account_KeyRotationEvent($old_authentication_key: Vec (int), $new_authentication_key: Vec (int)) -} -function {:inline} $Update'$1_account_KeyRotationEvent'_old_authentication_key(s: $1_account_KeyRotationEvent, x: Vec (int)): $1_account_KeyRotationEvent { - $1_account_KeyRotationEvent(x, s->$new_authentication_key) -} -function {:inline} $Update'$1_account_KeyRotationEvent'_new_authentication_key(s: $1_account_KeyRotationEvent, x: Vec (int)): $1_account_KeyRotationEvent { - $1_account_KeyRotationEvent(s->$old_authentication_key, x) -} -function $IsValid'$1_account_KeyRotationEvent'(s: $1_account_KeyRotationEvent): bool { - $IsValid'vec'u8''(s->$old_authentication_key) - && $IsValid'vec'u8''(s->$new_authentication_key) -} -function {:inline} $IsEqual'$1_account_KeyRotationEvent'(s1: $1_account_KeyRotationEvent, s2: $1_account_KeyRotationEvent): bool { - $IsEqual'vec'u8''(s1->$old_authentication_key, s2->$old_authentication_key) - && $IsEqual'vec'u8''(s1->$new_authentication_key, s2->$new_authentication_key)} - -// struct account::RotationCapability at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:88:5+62 -datatype $1_account_RotationCapability { - $1_account_RotationCapability($account: int) -} -function {:inline} $Update'$1_account_RotationCapability'_account(s: $1_account_RotationCapability, x: int): $1_account_RotationCapability { - $1_account_RotationCapability(x) -} -function $IsValid'$1_account_RotationCapability'(s: $1_account_RotationCapability): bool { - $IsValid'address'(s->$account) -} -function {:inline} $IsEqual'$1_account_RotationCapability'(s1: $1_account_RotationCapability, s2: $1_account_RotationCapability): bool { - s1 == s2 -} - -// struct account::SignerCapability at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:90:5+60 -datatype $1_account_SignerCapability { - $1_account_SignerCapability($account: int) -} -function {:inline} $Update'$1_account_SignerCapability'_account(s: $1_account_SignerCapability, x: int): $1_account_SignerCapability { - $1_account_SignerCapability(x) -} -function $IsValid'$1_account_SignerCapability'(s: $1_account_SignerCapability): bool { - $IsValid'address'(s->$account) -} -function {:inline} $IsEqual'$1_account_SignerCapability'(s1: $1_account_SignerCapability, s2: $1_account_SignerCapability): bool { - s1 == s2 -} - -// fun account::get_sequence_number [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:384:5+328 -procedure {:inline 1} $1_account_get_sequence_number(_$t0: int) returns ($ret0: int) -{ - // declare local variables - var $t1: int; - var $t2: bool; - var $t3: $1_account_Account; - var $t4: int; - var $t5: int; - var $t6: bool; - var $t7: int; - var $t8: int; - var $t9: int; - var $t0: int; - var $temp_0'address': int; - var $temp_0'u64': int; - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[addr]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:384:5+1 - assume {:print "$at(98,18599,18600)"} true; - assume {:print "$track_local(39,16,0):", $t0} $t0 == $t0; - - // $t2 := exists<0x1::account::Account>($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:360:9+21 - assume {:print "$at(98,17757,17778)"} true; - $t2 := $ResourceExists($1_account_Account_$memory, $t0); - - // if ($t2) goto L1 else goto L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 - assume {:print "$at(98,18677,18921)"} true; - if ($t2) { goto L1; } else { goto L0; } - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+13 - assume {:print "$at(98,18721,18734)"} true; -L1: - - // $t3 := get_global<0x1::account::Account>($t0) on_abort goto L6 with $t4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+13 - assume {:print "$at(98,18721,18734)"} true; - if (!$ResourceExists($1_account_Account_$memory, $t0)) { - call $ExecFailureAbort(); - } else { - $t3 := $ResourceValue($1_account_Account_$memory, $t0); - } - if ($abort_flag) { - assume {:print "$at(98,18721,18734)"} true; - $t4 := $abort_code; - assume {:print "$track_abort(39,16):", $t4} $t4 == $t4; - goto L6; - } - - // $t5 := get_field<0x1::account::Account>.sequence_number($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+29 - $t5 := $t3->$sequence_number; - - // $t1 := $t5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+29 - $t1 := $t5; - - // trace_local[return]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:386:13+29 - assume {:print "$track_local(39,16,1):", $t5} $t5 == $t5; - - // label L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 - assume {:print "$at(98,18677,18921)"} true; -L4: - - // trace_return[0]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 - assume {:print "$at(98,18677,18921)"} true; - assume {:print "$track_return(39,16,0):", $t1} $t1 == $t1; - - // goto L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:385:9+244 - goto L5; - - // label L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 - assume {:print "$at(98,18770,18817)"} true; -L0: - - // $t6 := opaque begin: features::is_default_account_resource_enabled() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 - assume {:print "$at(98,18770,18817)"} true; - - // assume WellFormed($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 - assume $IsValid'bool'($t6); - - // assume Eq($t6, features::spec_is_enabled(91)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 - assume $IsEqual'bool'($t6, $1_features_spec_is_enabled(91)); - - // $t6 := opaque end: features::is_default_account_resource_enabled() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:20+47 - - // if ($t6) goto L3 else goto L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:387:16+155 - if ($t6) { goto L3; } else { goto L2; } - - // label L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 - assume {:print "$at(98,18833,18834)"} true; -L3: - - // $t7 := 0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 - assume {:print "$at(98,18833,18834)"} true; - $t7 := 0; - assume $IsValid'u64'($t7); - - // $t1 := $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 - $t1 := $t7; - - // trace_local[return]($t7) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 - assume {:print "$track_local(39,16,1):", $t7} $t7 == $t7; - - // goto L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:388:13+1 - goto L4; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:36+23 - assume {:print "$at(98,18887,18910)"} true; -L2: - - // $t8 := 2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:36+23 - assume {:print "$at(98,18887,18910)"} true; - $t8 := 2; - assume $IsValid'u64'($t8); - - // $t9 := error::not_found($t8) on_abort goto L6 with $t4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:19+41 - call $t9 := $1_error_not_found($t8); - if ($abort_flag) { - assume {:print "$at(98,18870,18911)"} true; - $t4 := $abort_code; - assume {:print "$track_abort(39,16):", $t4} $t4 == $t4; - goto L6; - } - - // trace_abort($t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:13+47 - assume {:print "$at(98,18864,18911)"} true; - assume {:print "$track_abort(39,16):", $t9} $t9 == $t9; - - // $t4 := move($t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:13+47 - $t4 := $t9; - - // goto L6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:390:13+47 - goto L6; - - // label L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 - assume {:print "$at(98,18926,18927)"} true; -L5: - - // return $t1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 - assume {:print "$at(98,18926,18927)"} true; - $ret0 := $t1; - return; - - // label L6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 -L6: - - // abort($t4) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/account/account.move:392:5+1 - assume {:print "$at(98,18926,18927)"} true; - $abort_code := $t4; - $abort_flag := true; - return; - -} - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:7:9+50 -function $1_aptos_hash_spec_keccak256(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_aptos_hash_spec_keccak256(bytes); -$IsValid'vec'u8''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:12:9+58 -function $1_aptos_hash_spec_sha2_512_internal(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_aptos_hash_spec_sha2_512_internal(bytes); -$IsValid'vec'u8''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:17:9+58 -function $1_aptos_hash_spec_sha3_512_internal(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_aptos_hash_spec_sha3_512_internal(bytes); -$IsValid'vec'u8''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:22:9+59 -function $1_aptos_hash_spec_ripemd160_internal(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_aptos_hash_spec_ripemd160_internal(bytes); -$IsValid'vec'u8''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/../aptos-stdlib/sources/hash.spec.move:27:9+61 -function $1_aptos_hash_spec_blake2b_256_internal(bytes: Vec (int)): Vec (int); -axiom (forall bytes: Vec (int) :: -(var $$res := $1_aptos_hash_spec_blake2b_256_internal(bytes); -$IsValid'vec'u8''($$res))); - -// spec fun at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/reconfiguration.move:168:5+155 -function {:inline} $1_reconfiguration_$last_reconfiguration_time($1_reconfiguration_Configuration_$memory: $Memory $1_reconfiguration_Configuration): int { - $ResourceValue($1_reconfiguration_Configuration_$memory, 1)->$last_reconfiguration_time -} - -// struct reconfiguration::Configuration at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/reconfiguration.move:43:5+306 -datatype $1_reconfiguration_Configuration { - $1_reconfiguration_Configuration($epoch: int, $last_reconfiguration_time: int, $events: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent') -} -function {:inline} $Update'$1_reconfiguration_Configuration'_epoch(s: $1_reconfiguration_Configuration, x: int): $1_reconfiguration_Configuration { - $1_reconfiguration_Configuration(x, s->$last_reconfiguration_time, s->$events) -} -function {:inline} $Update'$1_reconfiguration_Configuration'_last_reconfiguration_time(s: $1_reconfiguration_Configuration, x: int): $1_reconfiguration_Configuration { - $1_reconfiguration_Configuration(s->$epoch, x, s->$events) -} -function {:inline} $Update'$1_reconfiguration_Configuration'_events(s: $1_reconfiguration_Configuration, x: $1_event_EventHandle'$1_reconfiguration_NewEpochEvent'): $1_reconfiguration_Configuration { - $1_reconfiguration_Configuration(s->$epoch, s->$last_reconfiguration_time, x) -} -function $IsValid'$1_reconfiguration_Configuration'(s: $1_reconfiguration_Configuration): bool { - $IsValid'u64'(s->$epoch) - && $IsValid'u64'(s->$last_reconfiguration_time) - && $IsValid'$1_event_EventHandle'$1_reconfiguration_NewEpochEvent''(s->$events) -} -function {:inline} $IsEqual'$1_reconfiguration_Configuration'(s1: $1_reconfiguration_Configuration, s2: $1_reconfiguration_Configuration): bool { - s1 == s2 -} -var $1_reconfiguration_Configuration_$memory: $Memory $1_reconfiguration_Configuration; - -// struct reconfiguration::NewEpochEvent at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/reconfiguration.move:30:5+64 -datatype $1_reconfiguration_NewEpochEvent { - $1_reconfiguration_NewEpochEvent($epoch: int) -} -function {:inline} $Update'$1_reconfiguration_NewEpochEvent'_epoch(s: $1_reconfiguration_NewEpochEvent, x: int): $1_reconfiguration_NewEpochEvent { - $1_reconfiguration_NewEpochEvent(x) -} -function $IsValid'$1_reconfiguration_NewEpochEvent'(s: $1_reconfiguration_NewEpochEvent): bool { - $IsValid'u64'(s->$epoch) -} -function {:inline} $IsEqual'$1_reconfiguration_NewEpochEvent'(s1: $1_reconfiguration_NewEpochEvent, s2: $1_reconfiguration_NewEpochEvent): bool { - s1 == s2 -} - -// struct timelock::CreateTransaction at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:155:5+189 -datatype $1_timelock_CreateTransaction { - $1_timelock_CreateTransaction($timelock_account: int, $creator: int, $transaction_hash: Vec (int), $transaction: $1_timelock_TimelockTransaction) -} -function {:inline} $Update'$1_timelock_CreateTransaction'_timelock_account(s: $1_timelock_CreateTransaction, x: int): $1_timelock_CreateTransaction { - $1_timelock_CreateTransaction(x, s->$creator, s->$transaction_hash, s->$transaction) -} -function {:inline} $Update'$1_timelock_CreateTransaction'_creator(s: $1_timelock_CreateTransaction, x: int): $1_timelock_CreateTransaction { - $1_timelock_CreateTransaction(s->$timelock_account, x, s->$transaction_hash, s->$transaction) -} -function {:inline} $Update'$1_timelock_CreateTransaction'_transaction_hash(s: $1_timelock_CreateTransaction, x: Vec (int)): $1_timelock_CreateTransaction { - $1_timelock_CreateTransaction(s->$timelock_account, s->$creator, x, s->$transaction) -} -function {:inline} $Update'$1_timelock_CreateTransaction'_transaction(s: $1_timelock_CreateTransaction, x: $1_timelock_TimelockTransaction): $1_timelock_CreateTransaction { - $1_timelock_CreateTransaction(s->$timelock_account, s->$creator, s->$transaction_hash, x) -} -function $IsValid'$1_timelock_CreateTransaction'(s: $1_timelock_CreateTransaction): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'address'(s->$creator) - && $IsValid'vec'u8''(s->$transaction_hash) - && $IsValid'$1_timelock_TimelockTransaction'(s->$transaction) -} -function {:inline} $IsEqual'$1_timelock_CreateTransaction'(s1: $1_timelock_CreateTransaction, s2: $1_timelock_CreateTransaction): bool { - $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) - && $IsEqual'address'(s1->$creator, s2->$creator) - && $IsEqual'vec'u8''(s1->$transaction_hash, s2->$transaction_hash) - && $IsEqual'$1_timelock_TimelockTransaction'(s1->$transaction, s2->$transaction)} - -// struct timelock::AddCreators at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:124:5+118 -datatype $1_timelock_AddCreators { - $1_timelock_AddCreators($timelock_account: int, $creators_added: Vec (int)) -} -function {:inline} $Update'$1_timelock_AddCreators'_timelock_account(s: $1_timelock_AddCreators, x: int): $1_timelock_AddCreators { - $1_timelock_AddCreators(x, s->$creators_added) -} -function {:inline} $Update'$1_timelock_AddCreators'_creators_added(s: $1_timelock_AddCreators, x: Vec (int)): $1_timelock_AddCreators { - $1_timelock_AddCreators(s->$timelock_account, x) -} -function $IsValid'$1_timelock_AddCreators'(s: $1_timelock_AddCreators): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'vec'address''(s->$creators_added) -} -function {:inline} $IsEqual'$1_timelock_AddCreators'(s1: $1_timelock_AddCreators, s2: $1_timelock_AddCreators): bool { - $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) - && $IsEqual'vec'address''(s1->$creators_added, s2->$creators_added)} - -// struct timelock::AddExecutors at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:136:5+120 -datatype $1_timelock_AddExecutors { - $1_timelock_AddExecutors($timelock_account: int, $executors_added: Vec (int)) -} -function {:inline} $Update'$1_timelock_AddExecutors'_timelock_account(s: $1_timelock_AddExecutors, x: int): $1_timelock_AddExecutors { - $1_timelock_AddExecutors(x, s->$executors_added) -} -function {:inline} $Update'$1_timelock_AddExecutors'_executors_added(s: $1_timelock_AddExecutors, x: Vec (int)): $1_timelock_AddExecutors { - $1_timelock_AddExecutors(s->$timelock_account, x) -} -function $IsValid'$1_timelock_AddExecutors'(s: $1_timelock_AddExecutors): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'vec'address''(s->$executors_added) -} -function {:inline} $IsEqual'$1_timelock_AddExecutors'(s1: $1_timelock_AddExecutors, s2: $1_timelock_AddExecutors): bool { - $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) - && $IsEqual'vec'address''(s1->$executors_added, s2->$executors_added)} - -// struct timelock::CancelTransaction at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:163:5+145 -datatype $1_timelock_CancelTransaction { - $1_timelock_CancelTransaction($timelock_account: int, $actor: int, $transaction_hash: Vec (int)) -} -function {:inline} $Update'$1_timelock_CancelTransaction'_timelock_account(s: $1_timelock_CancelTransaction, x: int): $1_timelock_CancelTransaction { - $1_timelock_CancelTransaction(x, s->$actor, s->$transaction_hash) -} -function {:inline} $Update'$1_timelock_CancelTransaction'_actor(s: $1_timelock_CancelTransaction, x: int): $1_timelock_CancelTransaction { - $1_timelock_CancelTransaction(s->$timelock_account, x, s->$transaction_hash) -} -function {:inline} $Update'$1_timelock_CancelTransaction'_transaction_hash(s: $1_timelock_CancelTransaction, x: Vec (int)): $1_timelock_CancelTransaction { - $1_timelock_CancelTransaction(s->$timelock_account, s->$actor, x) -} -function $IsValid'$1_timelock_CancelTransaction'(s: $1_timelock_CancelTransaction): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'address'(s->$actor) - && $IsValid'vec'u8''(s->$transaction_hash) -} -function {:inline} $IsEqual'$1_timelock_CancelTransaction'(s1: $1_timelock_CancelTransaction, s2: $1_timelock_CancelTransaction): bool { - $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) - && $IsEqual'address'(s1->$actor, s2->$actor) - && $IsEqual'vec'u8''(s1->$transaction_hash, s2->$transaction_hash)} - -// struct timelock::RemoveCreators at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:130:5+123 -datatype $1_timelock_RemoveCreators { - $1_timelock_RemoveCreators($timelock_account: int, $creators_removed: Vec (int)) -} -function {:inline} $Update'$1_timelock_RemoveCreators'_timelock_account(s: $1_timelock_RemoveCreators, x: int): $1_timelock_RemoveCreators { - $1_timelock_RemoveCreators(x, s->$creators_removed) -} -function {:inline} $Update'$1_timelock_RemoveCreators'_creators_removed(s: $1_timelock_RemoveCreators, x: Vec (int)): $1_timelock_RemoveCreators { - $1_timelock_RemoveCreators(s->$timelock_account, x) -} -function $IsValid'$1_timelock_RemoveCreators'(s: $1_timelock_RemoveCreators): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'vec'address''(s->$creators_removed) -} -function {:inline} $IsEqual'$1_timelock_RemoveCreators'(s1: $1_timelock_RemoveCreators, s2: $1_timelock_RemoveCreators): bool { - $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) - && $IsEqual'vec'address''(s1->$creators_removed, s2->$creators_removed)} - -// struct timelock::RemoveExecutors at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:142:5+125 -datatype $1_timelock_RemoveExecutors { - $1_timelock_RemoveExecutors($timelock_account: int, $executors_removed: Vec (int)) -} -function {:inline} $Update'$1_timelock_RemoveExecutors'_timelock_account(s: $1_timelock_RemoveExecutors, x: int): $1_timelock_RemoveExecutors { - $1_timelock_RemoveExecutors(x, s->$executors_removed) -} -function {:inline} $Update'$1_timelock_RemoveExecutors'_executors_removed(s: $1_timelock_RemoveExecutors, x: Vec (int)): $1_timelock_RemoveExecutors { - $1_timelock_RemoveExecutors(s->$timelock_account, x) -} -function $IsValid'$1_timelock_RemoveExecutors'(s: $1_timelock_RemoveExecutors): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'vec'address''(s->$executors_removed) -} -function {:inline} $IsEqual'$1_timelock_RemoveExecutors'(s1: $1_timelock_RemoveExecutors, s2: $1_timelock_RemoveExecutors): bool { - $IsEqual'address'(s1->$timelock_account, s2->$timelock_account) - && $IsEqual'vec'address''(s1->$executors_removed, s2->$executors_removed)} - -// struct timelock::TimelockAccount at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:88:5+784 -datatype $1_timelock_TimelockAccount { - $1_timelock_TimelockAccount($creators: Vec (int), $executors: Vec (int), $min_num_seconds_execute: int, $transactions: Table int ($1_timelock_TimelockTransaction), $signer_cap: $1_account_SignerCapability) -} -function {:inline} $Update'$1_timelock_TimelockAccount'_creators(s: $1_timelock_TimelockAccount, x: Vec (int)): $1_timelock_TimelockAccount { - $1_timelock_TimelockAccount(x, s->$executors, s->$min_num_seconds_execute, s->$transactions, s->$signer_cap) -} -function {:inline} $Update'$1_timelock_TimelockAccount'_executors(s: $1_timelock_TimelockAccount, x: Vec (int)): $1_timelock_TimelockAccount { - $1_timelock_TimelockAccount(s->$creators, x, s->$min_num_seconds_execute, s->$transactions, s->$signer_cap) -} -function {:inline} $Update'$1_timelock_TimelockAccount'_min_num_seconds_execute(s: $1_timelock_TimelockAccount, x: int): $1_timelock_TimelockAccount { - $1_timelock_TimelockAccount(s->$creators, s->$executors, x, s->$transactions, s->$signer_cap) -} -function {:inline} $Update'$1_timelock_TimelockAccount'_transactions(s: $1_timelock_TimelockAccount, x: Table int ($1_timelock_TimelockTransaction)): $1_timelock_TimelockAccount { - $1_timelock_TimelockAccount(s->$creators, s->$executors, s->$min_num_seconds_execute, x, s->$signer_cap) -} -function {:inline} $Update'$1_timelock_TimelockAccount'_signer_cap(s: $1_timelock_TimelockAccount, x: $1_account_SignerCapability): $1_timelock_TimelockAccount { - $1_timelock_TimelockAccount(s->$creators, s->$executors, s->$min_num_seconds_execute, s->$transactions, x) -} -function $IsValid'$1_timelock_TimelockAccount'(s: $1_timelock_TimelockAccount): bool { - $IsValid'vec'address''(s->$creators) - && $IsValid'vec'address''(s->$executors) - && $IsValid'u64'(s->$min_num_seconds_execute) - && $IsValid'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(s->$transactions) - && $IsValid'$1_account_SignerCapability'(s->$signer_cap) -} -function {:inline} $IsEqual'$1_timelock_TimelockAccount'(s1: $1_timelock_TimelockAccount, s2: $1_timelock_TimelockAccount): bool { - $IsEqual'vec'address''(s1->$creators, s2->$creators) - && $IsEqual'vec'address''(s1->$executors, s2->$executors) - && $IsEqual'u64'(s1->$min_num_seconds_execute, s2->$min_num_seconds_execute) - && $IsEqual'$1_table_Table'vec'u8'_$1_timelock_TimelockTransaction''(s1->$transactions, s2->$transactions) - && $IsEqual'$1_account_SignerCapability'(s1->$signer_cap, s2->$signer_cap)} -var $1_timelock_TimelockAccount_$memory: $Memory $1_timelock_TimelockAccount; - -// struct timelock::TimelockTransaction at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:107:5+631 -datatype $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction($execution_hash: Vec (int), $creator: int, $creation_time_secs: int, $num_seconds_execute: int, $salt: Vec (int), $executed: bool) -} -function {:inline} $Update'$1_timelock_TimelockTransaction'_execution_hash(s: $1_timelock_TimelockTransaction, x: Vec (int)): $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction(x, s->$creator, s->$creation_time_secs, s->$num_seconds_execute, s->$salt, s->$executed) -} -function {:inline} $Update'$1_timelock_TimelockTransaction'_creator(s: $1_timelock_TimelockTransaction, x: int): $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction(s->$execution_hash, x, s->$creation_time_secs, s->$num_seconds_execute, s->$salt, s->$executed) -} -function {:inline} $Update'$1_timelock_TimelockTransaction'_creation_time_secs(s: $1_timelock_TimelockTransaction, x: int): $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, x, s->$num_seconds_execute, s->$salt, s->$executed) -} -function {:inline} $Update'$1_timelock_TimelockTransaction'_num_seconds_execute(s: $1_timelock_TimelockTransaction, x: int): $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, s->$creation_time_secs, x, s->$salt, s->$executed) -} -function {:inline} $Update'$1_timelock_TimelockTransaction'_salt(s: $1_timelock_TimelockTransaction, x: Vec (int)): $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, s->$creation_time_secs, s->$num_seconds_execute, x, s->$executed) -} -function {:inline} $Update'$1_timelock_TimelockTransaction'_executed(s: $1_timelock_TimelockTransaction, x: bool): $1_timelock_TimelockTransaction { - $1_timelock_TimelockTransaction(s->$execution_hash, s->$creator, s->$creation_time_secs, s->$num_seconds_execute, s->$salt, x) -} -function $IsValid'$1_timelock_TimelockTransaction'(s: $1_timelock_TimelockTransaction): bool { - $IsValid'vec'u8''(s->$execution_hash) - && $IsValid'address'(s->$creator) - && $IsValid'u64'(s->$creation_time_secs) - && $IsValid'u64'(s->$num_seconds_execute) - && $IsValid'vec'u8''(s->$salt) - && $IsValid'bool'(s->$executed) -} -function {:inline} $IsEqual'$1_timelock_TimelockTransaction'(s1: $1_timelock_TimelockTransaction, s2: $1_timelock_TimelockTransaction): bool { - $IsEqual'vec'u8''(s1->$execution_hash, s2->$execution_hash) - && $IsEqual'address'(s1->$creator, s2->$creator) - && $IsEqual'u64'(s1->$creation_time_secs, s2->$creation_time_secs) - && $IsEqual'u64'(s1->$num_seconds_execute, s2->$num_seconds_execute) - && $IsEqual'vec'u8''(s1->$salt, s2->$salt) - && $IsEqual'bool'(s1->$executed, s2->$executed)} - -// struct timelock::UpdateMinNumSecondsExecute at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:148:5+176 -datatype $1_timelock_UpdateMinNumSecondsExecute { - $1_timelock_UpdateMinNumSecondsExecute($timelock_account: int, $old_min_num_seconds_execute: int, $new_min_num_seconds_execute: int) -} -function {:inline} $Update'$1_timelock_UpdateMinNumSecondsExecute'_timelock_account(s: $1_timelock_UpdateMinNumSecondsExecute, x: int): $1_timelock_UpdateMinNumSecondsExecute { - $1_timelock_UpdateMinNumSecondsExecute(x, s->$old_min_num_seconds_execute, s->$new_min_num_seconds_execute) -} -function {:inline} $Update'$1_timelock_UpdateMinNumSecondsExecute'_old_min_num_seconds_execute(s: $1_timelock_UpdateMinNumSecondsExecute, x: int): $1_timelock_UpdateMinNumSecondsExecute { - $1_timelock_UpdateMinNumSecondsExecute(s->$timelock_account, x, s->$new_min_num_seconds_execute) -} -function {:inline} $Update'$1_timelock_UpdateMinNumSecondsExecute'_new_min_num_seconds_execute(s: $1_timelock_UpdateMinNumSecondsExecute, x: int): $1_timelock_UpdateMinNumSecondsExecute { - $1_timelock_UpdateMinNumSecondsExecute(s->$timelock_account, s->$old_min_num_seconds_execute, x) -} -function $IsValid'$1_timelock_UpdateMinNumSecondsExecute'(s: $1_timelock_UpdateMinNumSecondsExecute): bool { - $IsValid'address'(s->$timelock_account) - && $IsValid'u64'(s->$old_min_num_seconds_execute) - && $IsValid'u64'(s->$new_min_num_seconds_execute) -} -function {:inline} $IsEqual'$1_timelock_UpdateMinNumSecondsExecute'(s1: $1_timelock_UpdateMinNumSecondsExecute, s2: $1_timelock_UpdateMinNumSecondsExecute): bool { - s1 == s2 -} - -// fun timelock::get_transaction_hash [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:5+196 -procedure {:inline 1} $1_timelock_get_transaction_hash(_$t0: Vec (int), _$t1: Vec (int)) returns ($ret0: Vec (int)) -{ - // declare local variables - var $t2: Vec (int); - var $t3: $Mutation (Vec (int)); - var $t4: int; - var $t5: Vec (int); - var $t6: Vec (int); - var $t0: Vec (int); - var $t1: Vec (int); - var $temp_0'vec'u8'': Vec (int); - $t0 := _$t0; - $t1 := _$t1; - - // bytecode translation starts here - // trace_local[execution_hash]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:5+1 - assume {:print "$at(2,11385,11386)"} true; - assume {:print "$track_local(102,0,0):", $t0} $t0 == $t0; - - // trace_local[salt]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:5+1 - assume {:print "$track_local(102,0,1):", $t1} $t1 == $t1; - - // $t2 := $t0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:257:21+19 - assume {:print "$at(2,11497,11516)"} true; - $t2 := $t0; - - // trace_local[bytes]($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:257:21+19 - assume {:print "$track_local(102,0,2):", $t2} $t2 == $t2; - - // $t3 := borrow_local($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 - assume {:print "$at(2,11526,11549)"} true; - $t3 := $Mutation($Local(2), EmptyVec(), $t2); - - // vector::append($t3, $t1) on_abort goto L2 with $t4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 - call $t3 := $1_vector_append'u8'($t3, $t1); - if ($abort_flag) { - assume {:print "$at(2,11526,11549)"} true; - $t4 := $abort_code; - assume {:print "$track_abort(102,0):", $t4} $t4 == $t4; - goto L2; - } - - // write_back[LocalRoot($t2)@]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 - $t2 := $Dereference($t3); - - // trace_local[bytes]($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:258:9+23 - assume {:print "$track_local(102,0,2):", $t2} $t2 == $t2; - - // $t5 := move($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 - assume {:print "$at(2,11559,11575)"} true; - $t5 := $t2; - - // $t6 := opaque begin: aptos_hash::keccak256($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 - - // assume WellFormed($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 - assume $IsValid'vec'u8''($t6); - - // assume Eq>($t6, aptos_hash::spec_keccak256($t5)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 - assume $IsEqual'vec'u8''($t6, $1_aptos_hash_spec_keccak256($t5)); - - // $t6 := opaque end: aptos_hash::keccak256($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:259:9+16 - - // trace_return[0]($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:256:95+106 - assume {:print "$at(2,11475,11581)"} true; - assume {:print "$track_return(102,0,0):", $t6} $t6 == $t6; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 - assume {:print "$at(2,11580,11581)"} true; -L1: - - // return $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 - assume {:print "$at(2,11580,11581)"} true; - $ret0 := $t6; - return; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 -L2: - - // abort($t4) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:260:5+1 - assume {:print "$at(2,11580,11581)"} true; - $abort_code := $t4; - $abort_flag := true; - return; - -} - -// fun timelock::create_timelock_account_seed [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:571:5+210 -procedure {:inline 1} $1_timelock_create_timelock_account_seed(_$t0: Vec (int)) returns ($ret0: Vec (int)) -{ - // declare local variables - var $t1: Vec (int); - var $t2: int; - var $t3: $Mutation (Vec (int)); - var $t4: Vec (int); - var $t5: $Mutation (Vec (int)); - var $t6: Vec (int); - var $t0: Vec (int); - var $temp_0'vec'u8'': Vec (int); - $t0 := _$t0; - - // bytecode translation starts here - // trace_local[seed]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:571:5+1 - assume {:print "$at(2,26195,26196)"} true; - assume {:print "$track_local(102,14,0):", $t0} $t0 == $t0; - - // $t1 := vector::empty() on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:572:28+6 - assume {:print "$at(2,26287,26293)"} true; - call $t1 := $1_vector_empty'u8'(); - if ($abort_flag) { - assume {:print "$at(2,26287,26293)"} true; - $t2 := $abort_code; - assume {:print "$track_abort(102,14):", $t2} $t2 == $t2; - goto L2; - } - - // trace_local[account_seed]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:572:28+6 - assume {:print "$track_local(102,14,1):", $t1} $t1 == $t1; - - // $t3 := borrow_local($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 - assume {:print "$at(2,26305,26342)"} true; - $t3 := $Mutation($Local(1), EmptyVec(), $t1); - - // $t4 := [97, 112, 116, 111, 115, 95, 102, 114, 97, 109, 101, 119, 111, 114, 107, 58, 58, 116, 105, 109, 101, 108, 111, 99, 107] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:29+16 - $t4 := ConcatVec(ConcatVec(ConcatVec(ConcatVec(ConcatVec(ConcatVec(MakeVec4(97, 112, 116, 111), MakeVec4(115, 95, 102, 114)), MakeVec4(97, 109, 101, 119)), MakeVec4(111, 114, 107, 58)), MakeVec4(58, 116, 105, 109)), MakeVec4(101, 108, 111, 99)), MakeVec1(107)); - assume $IsValid'vec'u8''($t4); - - // vector::append($t3, $t4) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 - call $t3 := $1_vector_append'u8'($t3, $t4); - if ($abort_flag) { - assume {:print "$at(2,26305,26342)"} true; - $t2 := $abort_code; - assume {:print "$track_abort(102,14):", $t2} $t2 == $t2; - goto L2; - } - - // write_back[LocalRoot($t1)@]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 - $t1 := $Dereference($t3); - - // trace_local[account_seed]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:573:9+37 - assume {:print "$track_local(102,14,1):", $t1} $t1 == $t1; - - // $t5 := borrow_local($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 - assume {:print "$at(2,26352,26377)"} true; - $t5 := $Mutation($Local(1), EmptyVec(), $t1); - - // vector::append($t5, $t0) on_abort goto L2 with $t2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 - call $t5 := $1_vector_append'u8'($t5, $t0); - if ($abort_flag) { - assume {:print "$at(2,26352,26377)"} true; - $t2 := $abort_code; - assume {:print "$track_abort(102,14):", $t2} $t2 == $t2; - goto L2; - } - - // write_back[LocalRoot($t1)@]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 - $t1 := $Dereference($t5); - - // trace_local[account_seed]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:574:9+25 - assume {:print "$track_local(102,14,1):", $t1} $t1 == $t1; - - // $t6 := move($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:575:9+12 - assume {:print "$at(2,26387,26399)"} true; - $t6 := $t1; - - // trace_return[0]($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:571:68+147 - assume {:print "$at(2,26258,26405)"} true; - assume {:print "$track_return(102,14,0):", $t6} $t6 == $t6; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 - assume {:print "$at(2,26404,26405)"} true; -L1: - - // return $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 - assume {:print "$at(2,26404,26405)"} true; - $ret0 := $t6; - return; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 -L2: - - // abort($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:576:5+1 - assume {:print "$at(2,26404,26405)"} true; - $abort_code := $t2; - $abort_flag := true; - return; - -} - -// fun timelock::is_creator [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:199:5+184 -procedure {:inline 1} $1_timelock_is_creator(_$t0: int, _$t1: int) returns ($ret0: bool) -{ - // declare local variables - var $t2: $1_timelock_TimelockAccount; - var $t3: int; - var $t4: Vec (int); - var $t5: bool; - var $t0: int; - var $t1: int; - var $temp_0'address': int; - var $temp_0'bool': bool; - $t0 := _$t0; - $t1 := _$t1; - - // bytecode translation starts here - // trace_local[addr]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:199:5+1 - assume {:print "$at(2,8797,8798)"} true; - assume {:print "$track_local(102,16,0):", $t0} $t0 == $t0; - - // trace_local[timelock_account]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:199:5+1 - assume {:print "$track_local(102,16,1):", $t1} $t1 == $t1; - - // $t2 := get_global<0x1::timelock::TimelockAccount>($t1) on_abort goto L2 with $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+48 - assume {:print "$at(2,8902,8950)"} true; - if (!$ResourceExists($1_timelock_TimelockAccount_$memory, $t1)) { - call $ExecFailureAbort(); - } else { - $t2 := $ResourceValue($1_timelock_TimelockAccount_$memory, $t1); - } - if ($abort_flag) { - assume {:print "$at(2,8902,8950)"} true; - $t3 := $abort_code; - assume {:print "$track_abort(102,16):", $t3} $t3 == $t3; - goto L2; - } - - // $t4 := get_field<0x1::timelock::TimelockAccount>.creators($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+73 - $t4 := $t2->$creators; - - // $t5 := vector::contains
($t4, $t0) on_abort goto L2 with $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+73 - call $t5 := $1_vector_contains'address'($t4, $t0); - if ($abort_flag) { - assume {:print "$at(2,8902,8975)"} true; - $t3 := $abort_code; - assume {:print "$track_abort(102,16):", $t3} $t3 == $t3; - goto L2; - } - - // trace_return[0]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:200:9+73 - assume {:print "$track_return(102,16,0):", $t5} $t5 == $t5; - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 - assume {:print "$at(2,8980,8981)"} true; -L1: - - // return $t5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 - assume {:print "$at(2,8980,8981)"} true; - $ret0 := $t5; - return; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 -L2: - - // abort($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:201:5+1 - assume {:print "$at(2,8980,8981)"} true; - $abort_code := $t3; - $abort_flag := true; - return; - -} - -// fun timelock::is_executor [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:206:5+341 -procedure {:inline 1} $1_timelock_is_executor(_$t0: int, _$t1: int) returns ($ret0: bool) -{ - // declare local variables - var $t2: $1_timelock_TimelockAccount; - var $t3: bool; - var $t4: $1_timelock_TimelockAccount; - var $t5: $1_timelock_TimelockAccount; - var $t6: int; - var $t7: Vec (int); - var $t8: bool; - var $t9: Vec (int); - var $t10: bool; - var $t11: Vec (int); - var $t12: bool; - var $t0: int; - var $t1: int; - var $temp_0'$1_timelock_TimelockAccount': $1_timelock_TimelockAccount; - var $temp_0'address': int; - var $temp_0'bool': bool; - $t0 := _$t0; - $t1 := _$t1; - - // bytecode translation starts here - // assume Identical($t4, global<0x1::timelock::TimelockAccount>($t1)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.spec.move:128:9+57 - assume {:print "$at(3,8349,8406)"} true; - assume ($t4 == $ResourceValue($1_timelock_TimelockAccount_$memory, $t1)); - - // trace_local[addr]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:206:5+1 - assume {:print "$at(2,9159,9160)"} true; - assume {:print "$track_local(102,17,0):", $t0} $t0 == $t0; - - // trace_local[timelock_account]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:206:5+1 - assume {:print "$track_local(102,17,1):", $t1} $t1 == $t1; - - // $t5 := get_global<0x1::timelock::TimelockAccount>($t1) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:207:24+48 - assume {:print "$at(2,9280,9328)"} true; - if (!$ResourceExists($1_timelock_TimelockAccount_$memory, $t1)) { - call $ExecFailureAbort(); - } else { - $t5 := $ResourceValue($1_timelock_TimelockAccount_$memory, $t1); - } - if ($abort_flag) { - assume {:print "$at(2,9280,9328)"} true; - $t6 := $abort_code; - assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; - goto L4; - } - - // trace_local[timelock]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:207:24+48 - assume {:print "$track_local(102,17,2):", $t5} $t5 == $t5; - - // $t7 := get_field<0x1::timelock::TimelockAccount>.executors($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:13+29 - assume {:print "$at(2,9342,9371)"} true; - $t7 := $t5->$executors; - - // $t8 := vector::is_empty
($t7) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:13+29 - call $t8 := $1_vector_is_empty'address'($t7); - if ($abort_flag) { - assume {:print "$at(2,9342,9371)"} true; - $t6 := $abort_code; - assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; - goto L4; - } - - // if ($t8) goto L1 else goto L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 - if ($t8) { goto L1; } else { goto L0; } - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 - assume {:print "$at(2,9387,9420)"} true; -L1: - - // $t9 := get_field<0x1::timelock::TimelockAccount>.creators($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 - assume {:print "$at(2,9387,9420)"} true; - $t9 := $t5->$creators; - - // $t10 := vector::contains
($t9, $t0) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 - call $t10 := $1_vector_contains'address'($t9, $t0); - if ($abort_flag) { - assume {:print "$at(2,9387,9420)"} true; - $t6 := $abort_code; - assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; - goto L4; - } - - // $t3 := $t10 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 - $t3 := $t10; - - // trace_local[$t4]($t10) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:209:13+33 - assume {:print "$track_local(102,17,3):", $t10} $t10 == $t10; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 - assume {:print "$at(2,9338,9494)"} true; -L2: - - // trace_return[0]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 - assume {:print "$at(2,9338,9494)"} true; - assume {:print "$track_return(102,17,0):", $t3} $t3 == $t3; - - // goto L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:208:9+156 - goto L3; - - // label L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 - assume {:print "$at(2,9450,9484)"} true; -L0: - - // $t11 := get_field<0x1::timelock::TimelockAccount>.executors($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 - assume {:print "$at(2,9450,9484)"} true; - $t11 := $t5->$executors; - - // $t12 := vector::contains
($t11, $t0) on_abort goto L4 with $t6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 - call $t12 := $1_vector_contains'address'($t11, $t0); - if ($abort_flag) { - assume {:print "$at(2,9450,9484)"} true; - $t6 := $abort_code; - assume {:print "$track_abort(102,17):", $t6} $t6 == $t6; - goto L4; - } - - // $t3 := $t12 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 - $t3 := $t12; - - // trace_local[$t4]($t12) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 - assume {:print "$track_local(102,17,3):", $t12} $t12 == $t12; - - // goto L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:211:13+34 - goto L2; - - // label L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 - assume {:print "$at(2,9499,9500)"} true; -L3: - - // return $t3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 - assume {:print "$at(2,9499,9500)"} true; - $ret0 := $t3; - return; - - // label L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 -L4: - - // abort($t6) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:213:5+1 - assume {:print "$at(2,9499,9500)"} true; - $abort_code := $t6; - $abort_flag := true; - return; - -} - -// fun timelock::validate_members [baseline] at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1008 -procedure {:inline 1} $1_timelock_validate_members(_$t0: Vec (int), _$t1: int, _$t2: int) returns () -{ - // declare local variables - var $t3: Vec (int); - var $t4: int; - var $t5: int; - var $t6: int; - var $t7: int; - var $t8: int; - var $t9: int; - var $t10: bool; - var $t11: int; - var $t12: bool; - var $t13: Vec (int); - var $t14: bool; - var $t15: int; - var $t16: int; - var $t17: int; - var $t18: $Mutation (Vec (int)); - var $t19: int; - var $t20: int; - var $t21: int; - var $t0: Vec (int); - var $t1: int; - var $t2: int; - var $temp_0'address': int; - var $temp_0'u64': int; - var $temp_0'vec'address'': Vec (int); - $t0 := _$t0; - $t1 := _$t1; - $t2 := _$t2; - - // bytecode translation starts here - // trace_local[members]($t0) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1 - assume {:print "$at(2,26666,26667)"} true; - assume {:print "$track_local(102,21,0):", $t0} $t0 == $t0; - - // trace_local[timelock_address]($t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1 - assume {:print "$track_local(102,21,1):", $t1} $t1 == $t1; - - // trace_local[duplicate_error]($t2) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:5+1 - assume {:print "$track_local(102,21,2):", $t2} $t2 == $t2; - - // $t3 := vector::empty
() on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:582:41+6 - assume {:print "$at(2,26805,26811)"} true; - call $t3 := $1_vector_empty'address'(); - if ($abort_flag) { - assume {:print "$at(2,26805,26811)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // trace_local[distinct]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:582:41+6 - assume {:print "$track_local(102,21,3):", $t3} $t3 == $t3; - - // $t8 := vector::length
($t0) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:583:21+16 - assume {:print "$at(2,26835,26851)"} true; - call $t8 := $1_vector_length'address'($t0); - if ($abort_flag) { - assume {:print "$at(2,26835,26851)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // trace_local[total]($t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:583:21+16 - assume {:print "$track_local(102,21,4):", $t8} $t8 == $t8; - - // $t9 := 0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:584:17+1 - assume {:print "$at(2,26869,26870)"} true; - $t9 := 0; - assume $IsValid'u64'($t9); - - // trace_local[i]($t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:584:17+1 - assume {:print "$track_local(102,21,5):", $t9} $t9 == $t9; - - // label L6 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:586:13+339 - assume {:print "$at(2,26901,27240)"} true; -L6: - - // assert Le($t9, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:587:17+21 - assume {:print "$at(2,26924,26945)"} true; - assert {:msg "assert_failed(2,26924,26945): base case of the loop invariant does not hold"} - ($t9 <= $t8); - - // assert Eq(Len
($t3), $t9) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:588:17+29 - assume {:print "$at(2,26962,26991)"} true; - assert {:msg "assert_failed(2,26962,26991): base case of the loop invariant does not hold"} - $IsEqual'num'(LenVec($t3), $t9); - - // assert forall k: num: Range(0, $t9): Eq
(Index($t3, k), Index($t0, k)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:589:17+54 - assume {:print "$at(2,27008,27062)"} true; - assert {:msg "assert_failed(2,27008,27062): base case of the loop invariant does not hold"} - (var $range_0 := $Range(0, $t9); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - ($IsEqual'address'(ReadVec($t3, k), ReadVec($t0, k)))))); - - // assert forall k: num: Range(0, $t9): Neq
(Index($t0, k), $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:590:17+59 - assume {:print "$at(2,27079,27138)"} true; - assert {:msg "assert_failed(2,27079,27138): base case of the loop invariant does not hold"} - (var $range_0 := $Range(0, $t9); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - (!$IsEqual'address'(ReadVec($t0, k), $t1))))); - - // assert forall k: num: Range(0, $t9): forall l: num: Range(0, k): Neq
(Index($t0, k), Index($t0, l)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume {:print "$at(2,27155,27226)"} true; - assert {:msg "assert_failed(2,27155,27226): base case of the loop invariant does not hold"} - (var $range_0 := $Range(0, $t9); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - ((var $range_2 := $Range(0, k); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var l := $i_3; - (!$IsEqual'address'(ReadVec($t0, k), ReadVec($t0, l)))))))))); - - // $t3 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t3; - - // assume WellFormed($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'vec'address''($t3); - - // $t5 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t5; - - // assume WellFormed($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'u64'($t5); - - // $t10 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t10; - - // assume WellFormed($t10) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'bool'($t10); - - // $t11 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t11; - - // assume WellFormed($t11) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'address'($t11); - - // $t12 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t12; - - // assume WellFormed($t12) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'bool'($t12); - - // $t13 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t13; - - // assume WellFormed($t13) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'vec'address''($t13); - - // $t14 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t14; - - // assume WellFormed($t14) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'bool'($t14); - - // $t15 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t15; - - // assume WellFormed($t15) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'u64'($t15); - - // $t16 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t16; - - // assume WellFormed($t16) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'u64'($t16); - - // $t17 := havoc[val]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t17; - - // assume WellFormed($t17) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'u64'($t17); - - // $t18 := havoc[mut_all]() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - havoc $t18; - - // assume WellFormed($t18) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume $IsValid'vec'address''($Dereference($t18)); - - // trace_local[distinct]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume {:print "$info(): enter loop, variable(s) distinct, i havocked and reassigned"} true; - assume {:print "$track_local(102,21,3):", $t3} $t3 == $t3; - - // trace_local[i]($t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume {:print "$track_local(102,21,5):", $t5} $t5 == $t5; - - // assume Not(AbortFlag()) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume {:print "$info(): loop invariant holds at current state"} true; - assume !$abort_flag; - - // assume Le($t5, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:587:17+21 - assume {:print "$at(2,26924,26945)"} true; - assume ($t5 <= $t8); - - // assume Eq(Len
($t3), $t5) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:588:17+29 - assume {:print "$at(2,26962,26991)"} true; - assume $IsEqual'num'(LenVec($t3), $t5); - - // assume forall k: num: Range(0, $t5): Eq
(Index($t3, k), Index($t0, k)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:589:17+54 - assume {:print "$at(2,27008,27062)"} true; - assume (var $range_0 := $Range(0, $t5); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - ($IsEqual'address'(ReadVec($t3, k), ReadVec($t0, k)))))); - - // assume forall k: num: Range(0, $t5): Neq
(Index($t0, k), $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:590:17+59 - assume {:print "$at(2,27079,27138)"} true; - assume (var $range_0 := $Range(0, $t5); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - (!$IsEqual'address'(ReadVec($t0, k), $t1))))); - - // assume forall k: num: Range(0, $t5): forall l: num: Range(0, k): Neq
(Index($t0, k), Index($t0, l)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume {:print "$at(2,27155,27226)"} true; - assume (var $range_0 := $Range(0, $t5); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - ((var $range_2 := $Range(0, k); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var l := $i_3; - (!$IsEqual'address'(ReadVec($t0, k), ReadVec($t0, l)))))))))); - - // $t10 := <($t5, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:593:13+9 - assume {:print "$at(2,27254,27263)"} true; - call $t10 := $Lt($t5, $t8); - - // if ($t10) goto L1 else goto L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 - assume {:print "$at(2,26880,27667)"} true; - if ($t10) { goto L1; } else { goto L0; } - - // label L1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:595:27+7 - assume {:print "$at(2,27303,27310)"} true; -L1: - - // $t11 := vector::borrow
($t0, $t5) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:595:27+17 - assume {:print "$at(2,27303,27320)"} true; - call $t11 := $1_vector_borrow'address'($t0, $t5); - if ($abort_flag) { - assume {:print "$at(2,27303,27320)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // trace_local[member]($t11) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:595:26+18 - assume {:print "$track_local(102,21,6):", $t11} $t11 == $t11; - - // $t12 := !=($t11, $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:597:17+26 - assume {:print "$at(2,27359,27385)"} true; - $t12 := !$IsEqual'address'($t11, $t1); - - // if ($t12) goto L3 else goto L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 - assume {:print "$at(2,27334,27340)"} true; - if ($t12) { goto L3; } else { goto L2; } - - // label L3 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 - assume {:print "$at(2,27496,27522)"} true; -L3: - - // $t13 := copy($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 - assume {:print "$at(2,27496,27522)"} true; - $t13 := $t3; - - // ($t14, $t15) := vector::index_of
($t13, $t11) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 - call $t14,$t15 := $1_vector_index_of'address'($t13, $t11); - if ($abort_flag) { - assume {:print "$at(2,27496,27522)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // drop($t15) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:600:30+26 - - // if ($t14) goto L4 else goto L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:21+6 - assume {:print "$at(2,27544,27550)"} true; - if ($t14) { goto L4; } else { goto L5; } - - // label L5 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 - assume {:print "$at(2,27607,27633)"} true; -L5: - - // $t18 := borrow_local($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 - assume {:print "$at(2,27607,27633)"} true; - $t18 := $Mutation($Local(3), EmptyVec(), $t3); - - // vector::push_back
($t18, $t11) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 - call $t18 := $1_vector_push_back'address'($t18, $t11); - if ($abort_flag) { - assume {:print "$at(2,27607,27633)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // write_back[LocalRoot($t3)@]($t18) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 - $t3 := $Dereference($t18); - - // trace_local[distinct]($t3) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:602:13+26 - assume {:print "$track_local(102,21,3):", $t3} $t3 == $t3; - - // $t16 := 1 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:603:21+1 - assume {:print "$at(2,27655,27656)"} true; - $t16 := 1; - assume $IsValid'u64'($t16); - - // $t17 := +($t5, $t16) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:603:17+5 - call $t17 := $AddU64($t5, $t16); - if ($abort_flag) { - assume {:print "$at(2,27651,27656)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // trace_local[i]($t17) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:603:13+9 - assume {:print "$track_local(102,21,5):", $t17} $t17 == $t17; - - // goto L7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 - assume {:print "$at(2,26880,27667)"} true; - goto L7; - - // label L4 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 - assume {:print "$at(2,27536,27542)"} true; -L4: - - // $t19 := error::invalid_argument($t2) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:29+40 - assume {:print "$at(2,27552,27592)"} true; - call $t19 := $1_error_invalid_argument($t2); - if ($abort_flag) { - assume {:print "$at(2,27552,27592)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // trace_abort($t19) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 - assume {:print "$at(2,27536,27542)"} true; - assume {:print "$track_abort(102,21):", $t19} $t19 == $t19; - - // $t7 := move($t19) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 - $t7 := $t19; - - // goto L9 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:601:13+6 - goto L9; - - // label L2 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 - assume {:print "$at(2,27334,27340)"} true; -L2: - - // $t20 := 10 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:598:41+22 - assume {:print "$at(2,27427,27449)"} true; - $t20 := 10; - assume $IsValid'u64'($t20); - - // $t21 := error::invalid_argument($t20) on_abort goto L9 with $t7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:598:17+47 - call $t21 := $1_error_invalid_argument($t20); - if ($abort_flag) { - assume {:print "$at(2,27403,27450)"} true; - $t7 := $abort_code; - assume {:print "$track_abort(102,21):", $t7} $t7 == $t7; - goto L9; - } - - // trace_abort($t21) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 - assume {:print "$at(2,27334,27340)"} true; - assume {:print "$track_abort(102,21):", $t21} $t21 == $t21; - - // $t7 := move($t21) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 - $t7 := $t21; - - // goto L9 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:596:13+6 - goto L9; - - // label L0 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 - assume {:print "$at(2,26880,27667)"} true; -L0: - - // goto L8 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:581:102+911 - assume {:print "$at(2,26763,27674)"} true; - goto L8; - - // label L7 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:585:9+787 - // Loop invariant checking block for the loop started with header: L6 - assume {:print "$at(2,26880,27667)"} true; -L7: - - // assert Le($t17, $t8) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:587:17+21 - assume {:print "$at(2,26924,26945)"} true; - assert {:msg "assert_failed(2,26924,26945): induction case of the loop invariant does not hold"} - ($t17 <= $t8); - - // assert Eq(Len
($t3), $t17) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:588:17+29 - assume {:print "$at(2,26962,26991)"} true; - assert {:msg "assert_failed(2,26962,26991): induction case of the loop invariant does not hold"} - $IsEqual'num'(LenVec($t3), $t17); - - // assert forall k: num: Range(0, $t17): Eq
(Index($t3, k), Index($t0, k)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:589:17+54 - assume {:print "$at(2,27008,27062)"} true; - assert {:msg "assert_failed(2,27008,27062): induction case of the loop invariant does not hold"} - (var $range_0 := $Range(0, $t17); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - ($IsEqual'address'(ReadVec($t3, k), ReadVec($t0, k)))))); - - // assert forall k: num: Range(0, $t17): Neq
(Index($t0, k), $t1) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:590:17+59 - assume {:print "$at(2,27079,27138)"} true; - assert {:msg "assert_failed(2,27079,27138): induction case of the loop invariant does not hold"} - (var $range_0 := $Range(0, $t17); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - (!$IsEqual'address'(ReadVec($t0, k), $t1))))); - - // assert forall k: num: Range(0, $t17): forall l: num: Range(0, k): Neq
(Index($t0, k), Index($t0, l)) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume {:print "$at(2,27155,27226)"} true; - assert {:msg "assert_failed(2,27155,27226): induction case of the loop invariant does not hold"} - (var $range_0 := $Range(0, $t17); (forall $i_1: int :: $InRange($range_0, $i_1) ==> (var k := $i_1; - ((var $range_2 := $Range(0, k); (forall $i_3: int :: $InRange($range_2, $i_3) ==> (var l := $i_3; - (!$IsEqual'address'(ReadVec($t0, k), ReadVec($t0, l)))))))))); - - // stop() at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:591:17+71 - assume false; - return; - - // label L8 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 - assume {:print "$at(2,27673,27674)"} true; -L8: - - // return () at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 - assume {:print "$at(2,27673,27674)"} true; - return; - - // label L9 at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 -L9: - - // abort($t7) at /Users/primata/movement/aptos-core/aptos-move/framework/aptos-framework/sources/timelock.move:605:5+1 - assume {:print "$at(2,27673,27674)"} true; - $abort_code := $t7; - $abort_flag := true; - return; - -} From ac690426a932ea6c23c5ba7ed6aeba44b9d6e98f Mon Sep 17 00:00:00 2001 From: primata Date: Thu, 4 Jun 2026 15:38:56 -0300 Subject: [PATCH 6/9] code review --- third_party/move/move-compiler-v2/src/fuzz.rs | 209 +++++++++++++++--- .../move/move-compiler-v2/src/fuzz_corpus.rs | 51 ++--- .../move/move-compiler-v2/src/plan_builder.rs | 15 +- .../tests/unit_test/test/fuzz_implicit.move | 23 ++ .../unit_test/test/fuzz_out_of_range.exp | 17 ++ .../unit_test/test/fuzz_out_of_range.move | 10 + .../move/tools/move-unit-test/src/lib.rs | 34 ++- .../tools/move-unit-test/src/test_runner.rs | 114 ++++++---- 8 files changed, 363 insertions(+), 110 deletions(-) create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.exp create mode 100644 third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.move diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs index 0e03b0c57ae..7df62724fb6 100644 --- a/third_party/move/move-compiler-v2/src/fuzz.rs +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -118,11 +118,12 @@ impl FuzzPlanMetadata { } pub fn get(&self, module_id: &ModuleId, test_name: &str) -> Option<&Vec> { - // ModuleId isn't Hash for BTreeMap lookup with (&_, &str); rebuild key. + // `entries` is keyed by the same `(ModuleId, String)` tuple used at + // insert time, and both components are `Ord`, so a direct keyed lookup + // is correct and O(log n) — no need to linear-scan. (A `&str` borrow of + // the tuple key isn't possible, so we rebuild an owned key.) self.entries - .iter() - .find(|((m, n), _)| m == module_id && n == test_name) - .map(|(_, v)| v) + .get(&(module_id.clone(), test_name.to_string())) } } @@ -574,6 +575,16 @@ fn sample_bools( exclude: &Domain, fixtures: Option<&FixturePool>, ) -> Result, String> { + // A range constraint (`b in lo..hi`) is meaningless for `bool` and would + // otherwise be silently dropped, leaving the domain unrestricted. Reject it + // with a clear diagnostic rather than ignoring the user's intent. + if !domain.ranges.is_empty() || !exclude.ranges.is_empty() { + return Err( + "fuzz: range constraints (`lo..hi`) are not supported on `bool` parameters; \ + use literals (e.g. `b in [true]` or `b != false`)" + .to_string(), + ); + } let dom_bools: Vec = domain.literals.iter().filter_map(extract_bool).collect(); let exc_bools: Vec = exclude.literals.iter().filter_map(extract_bool).collect(); let mut pool: Vec = if dom_bools.is_empty() { @@ -606,6 +617,10 @@ fn sample_addresses( dict: &FuzzDictionary, fixtures: Option<&FixturePool>, ) -> Result, String> { + // Reject range bounds that don't fit the 32-byte address space at + // plan-build time, so `bigint_to_address`'s truncation is never the thing + // that silently narrows a user's constraint. + validate_address_domain(domain, exclude)?; let dom_addrs: Vec = domain .literals .iter() @@ -674,6 +689,14 @@ fn sample_addresses( // `n` rather than returning fewer values and capping the run count. let literal_only = !dom_addrs.is_empty() && dom_ranges.is_empty(); + let random_address = |rng: &mut Rng| { + let mut bytes = [0u8; AccountAddress::LENGTH]; + for chunk in bytes.chunks_exact_mut(8) { + chunk.copy_from_slice(&rng.next_u64().to_le_bytes()); + } + AccountAddress::new(bytes) + }; + while out.len() < n && tries < cap { tries += 1; if literal_only { @@ -685,7 +708,21 @@ fn sample_addresses( continue; } let pick = rng.next_u64() % 100; - let candidate = if pick < u64::from(EDGE_WEIGHT) { + let is_edge = pick < u64::from(EDGE_WEIGHT); + let candidate = if !dom_ranges.is_empty() { + // A domain range is active. A full-width random address essentially + // never lands in a bounded interval, so sample *within* a randomly + // chosen range (mirroring `sample_uints`) instead of rejecting draws + // until the retry budget is exhausted. Spend the edge budget on + // range-bracketed boundary values for coverage, honoring the + // half-open upper bound so the excluded `hi` is never emitted. + let (lo, hi, inc) = rng.pick(&dom_ranges).unwrap(); + if is_edge { + bigint_to_address(range_edge_endpoint(rng, lo, hi, *inc)) + } else { + bigint_to_address(sample_bigint_in_range(rng, lo, hi, *inc)) + } + } else if is_edge { // Edge: well-known anchors. let edges = [ AccountAddress::ZERO, @@ -693,27 +730,10 @@ fn sample_addresses( AccountAddress::from_hex_literal("0x2").unwrap_or(AccountAddress::ONE), ]; *rng.pick(&edges).unwrap() - } else if !dict.addresses.is_empty() && pick < 100 { - // Dictionary, when available, otherwise random (handled below). + } else if !dict.addresses.is_empty() { *rng.pick(&dict.addresses).unwrap() } else { - let mut bytes = [0u8; AccountAddress::LENGTH]; - for chunk in bytes.chunks_exact_mut(8) { - chunk.copy_from_slice(&rng.next_u64().to_le_bytes()); - } - AccountAddress::new(bytes) - }; - let candidate = if dict.addresses.is_empty() && pick >= u64::from(EDGE_WEIGHT) && pick < 100 - { - // We fell into the "dictionary" branch but the dictionary is empty — - // synthesize a random address instead. - let mut bytes = [0u8; AccountAddress::LENGTH]; - for chunk in bytes.chunks_exact_mut(8) { - chunk.copy_from_slice(&rng.next_u64().to_le_bytes()); - } - AccountAddress::new(bytes) - } else { - candidate + random_address(rng) }; if !in_domain(&candidate) || is_excluded(&candidate) { continue; @@ -741,13 +761,19 @@ fn sample_uints( dictionary_weight: u8, max_retry_multiplier: usize, ) -> Result, String> { + // Reject constraint values that don't fit the type up front — the same + // policy `coerce_numeric_to_width` applies to concrete `#[test]` values — so + // `a != 300` on a `u8` is a clear error rather than a silently-wrapped + // `a != 44`. Once validated, every literal is in `[0, max]`, so membership + // checks line up with the reduced random candidates below. + validate_uint_domain(width, domain, exclude)?; + let edges = uint_edges(width); + let modulus = uint_modulus(width); let dom_lits: Vec = domain.literals.iter().filter_map(extract_bigint).collect(); let exc_lits: Vec = exclude.literals.iter().filter_map(extract_bigint).collect(); let dom_ranges = parse_int_ranges(&domain.ranges); let exc_ranges = parse_int_ranges(&exclude.ranges); let domain_active = !dom_lits.is_empty() || !dom_ranges.is_empty(); - let edges = uint_edges(width); - let modulus = uint_modulus(width); let is_excluded = |v: &BigInt| -> bool { exc_lits.contains(v) @@ -792,11 +818,11 @@ fn sample_uints( } } + // Pick weights partition [0,100): [0,edge_cutoff)=edge, [edge_cutoff, + // dict_cutoff)=dictionary, [dict_cutoff,100)=random (the fall-through). let dictionary_weight = dictionary_weight.min(100); - let random_weight = 100u64.saturating_sub(u64::from(dictionary_weight) + u64::from(EDGE_WEIGHT)); let edge_cutoff = u64::from(EDGE_WEIGHT); let dict_cutoff = edge_cutoff + u64::from(dictionary_weight); - let _ = random_weight; // documentation; the random branch is the fall-through let mut tries = 0usize; let cap = n.saturating_mul(max_retry_multiplier).max(1); @@ -817,12 +843,9 @@ fn sample_uints( } } else if pick < edge_cutoff { // Edge sample. If a domain range is active, draw an edge value - // bracketed against the active range — honoring the half-open - // upper bound so we never emit the excluded `hi`. + // bracketed against the active range; otherwise use the type edges. if let Some((lo, hi, inc)) = rng.pick(&dom_ranges).cloned() { - let hi_edge = if inc { hi } else { &hi - 1 }; - let endpoints = [lo.clone(), &lo + 1, &hi_edge - 1, hi_edge]; - rng.pick(&endpoints).cloned().unwrap_or_else(BigInt::default) + range_edge_endpoint(rng, &lo, &hi, inc) } else { rng.pick(&edges).cloned().unwrap_or_else(BigInt::default) } @@ -839,7 +862,7 @@ fn sample_uints( random_bigint_below(rng, &modulus) }; // Coerce candidate into the type's representable range. - let candidate = ((&candidate % &modulus) + &modulus) % &modulus; + let candidate = reduce_into_range(candidate, &modulus); if !in_domain(&candidate) || is_excluded(&candidate) { continue; } @@ -918,10 +941,104 @@ fn address_in_range(addr: &AccountAddress, lo: &BigInt, hi: &BigInt, inclusive_h in_int_range(&v, lo, hi, inclusive_hi) } +/// Reject `#[test]` fuzz constraints whose literal/range values don't fit the +/// integer width, mirroring the policy `coerce_numeric_to_width` enforces for +/// concrete values. Returning `Err` here surfaces as a labeled plan-build +/// diagnostic (see `materialize_param_values`), so an out-of-range constraint +/// is a clear compile error instead of a silently-wrapped value. +fn validate_uint_domain(width: UintWidth, domain: &Domain, exclude: &Domain) -> Result<(), String> { + let modulus = uint_modulus(width); + let max = &modulus - 1; + for v in domain + .literals + .iter() + .chain(exclude.literals.iter()) + .filter_map(extract_bigint) + { + if v > max { + return Err(format!( + "fuzz: value {} is out of range for this integer parameter (max {})", + v, max + )); + } + } + for r in domain.ranges.iter().chain(exclude.ranges.iter()) { + if let Some(lo) = extract_bigint(&r.lo) { + if lo > max { + return Err(format!( + "fuzz: range bound {} is out of range for this integer parameter (max {})", + lo, max + )); + } + } + if let Some(hi) = extract_bigint(&r.hi) { + // An exclusive upper bound may equal the modulus (it denotes "up to + // max, inclusive"); an inclusive one must be <= max. + let hi_limit = if r.inclusive_hi { &max } else { &modulus }; + if &hi > hi_limit { + return Err(format!( + "fuzz: range bound {} is out of range for this integer parameter (max {})", + hi, max + )); + } + } + } + Ok(()) +} + +/// Reject address-range bounds that don't fit the 32-byte address space, so the +/// generator (`bigint_to_address`) and the membership filter (`address_in_range`) +/// can never disagree about an out-of-space bound. +fn validate_address_domain(domain: &Domain, exclude: &Domain) -> Result<(), String> { + let max = (BigInt::from(1) << 256) - 1; + for r in domain.ranges.iter().chain(exclude.ranges.iter()) { + for bound in [&r.lo, &r.hi] { + if let Some(v) = extract_bigint(bound) { + if v.sign() == Sign::Minus || v > max { + return Err(format!( + "fuzz: address range bound {} does not fit the 32-byte address space", + v + )); + } + } + } + } + Ok(()) +} + +/// Interpret a `BigInt` as a 256-bit big-endian address. Negative inputs are +/// clamped to `0x0` (the bottom of the address space) — they can arise from +/// range-edge arithmetic on degenerate ranges and have no address meaning. +/// Values wider than 32 bytes are truncated to their low 32 bytes, matching +/// `address_in_range`'s big-endian interpretation. Address range bounds are +/// validated against the 32-byte space at plan-build time (see +/// `validate_address_domain`), so the truncation path is defensive only. +fn bigint_to_address(n: BigInt) -> AccountAddress { + if n.sign() == Sign::Minus { + return AccountAddress::ZERO; + } + let (_sign, be) = n.to_bytes_be(); + let mut buf = [0u8; AccountAddress::LENGTH]; + if be.len() >= AccountAddress::LENGTH { + buf.copy_from_slice(&be[be.len() - AccountAddress::LENGTH..]); + } else { + buf[AccountAddress::LENGTH - be.len()..].copy_from_slice(&be); + } + AccountAddress::new(buf) +} + // --------------------------------------------------------------------------- // Numeric helpers // --------------------------------------------------------------------------- +/// Reduce `n` into the half-open range `[0, modulus)`, handling negative +/// inputs. Used to coerce both sampled candidates and user-supplied literals +/// into a uint type's representable range so membership checks and emitted +/// values stay consistent. +fn reduce_into_range(n: BigInt, modulus: &BigInt) -> BigInt { + ((n % modulus) + modulus) % modulus +} + fn uint_modulus(width: UintWidth) -> BigInt { match width { UintWidth::U8 => BigInt::from(1u64) << 8, @@ -970,6 +1087,26 @@ fn sample_bigint_in_range(rng: &mut Rng, lo: &BigInt, hi: &BigInt, inclusive_hi: lo + raw % span } +/// Pick a boundary value for a range, honoring the half-open upper bound (so +/// the excluded `hi` is never returned). Every endpoint is clamped to `[lo, +/// hi_edge]`, so a degenerate range like `0..1` (whose naive `hi_edge - 1` +/// would be `-1`) yields only in-range values instead of negatives or +/// out-of-bounds picks. Shared by `sample_uints` and `sample_addresses`. +fn range_edge_endpoint(rng: &mut Rng, lo: &BigInt, hi: &BigInt, inclusive_hi: bool) -> BigInt { + let one = BigInt::from(1); + let hi_edge = if inclusive_hi { hi.clone() } else { hi - &one }; + if hi_edge <= *lo { + return lo.clone(); + } + let endpoints = [ + lo.clone(), + (lo + &one).min(hi_edge.clone()), + (&hi_edge - &one).max(lo.clone()), + hi_edge, + ]; + rng.pick(&endpoints).cloned().unwrap_or_else(|| lo.clone()) +} + fn limbs_to_u32(u64s: &[u64]) -> Vec { let mut out = Vec::with_capacity(u64s.len() * 2); for n in u64s { @@ -1184,7 +1321,7 @@ fn mutate_value( rng.pick(&lits).cloned().unwrap_or(cur.clone()) }, }; - let cand = ((&cand % &m) + &m) % &m; + let cand = reduce_into_range(cand, &m); if cand == cur { return None; } @@ -1290,7 +1427,7 @@ fn mutate_value( fn bigint_to_move_value(n: BigInt, width: UintWidth) -> Option { let m = uint_modulus(width); - let n = ((&n % &m) + &m) % &m; + let n = reduce_into_range(n, &m); match width { UintWidth::U8 => n.to_u64().map(|x| MoveValue::U8(x as u8)), UintWidth::U16 => n.to_u64().map(|x| MoveValue::U16(x as u16)), diff --git a/third_party/move/move-compiler-v2/src/fuzz_corpus.rs b/third_party/move/move-compiler-v2/src/fuzz_corpus.rs index 47720499105..94d15c44e35 100644 --- a/third_party/move/move-compiler-v2/src/fuzz_corpus.rs +++ b/third_party/move/move-compiler-v2/src/fuzz_corpus.rs @@ -171,16 +171,19 @@ pub fn load_seeds( read_corpus_file(&path) } -/// Append `args` to the failures file for `(module, test)`, de-duping against -/// the existing entries. Idempotent. -pub fn append_failure( +/// Append `args` to the `subdir` corpus file for `(module, test)`, de-duping +/// against the existing entries. Idempotent. `what` names the entry kind for +/// error context. +fn append_entry( corpus_dir: &Path, + subdir: &str, module_id: &ModuleId, test_name: &str, args: &[MoveValue], + what: &str, ) -> Result<()> { let path = corpus_dir - .join(FAILURES_SUBDIR) + .join(subdir) .join(corpus_filename(module_id, test_name)); let mut existing = if path.exists() { read_corpus_file(&path)? @@ -194,9 +197,9 @@ pub fn append_failure( let key = to_wire(args).and_then(|w| bcs::to_bytes(&w).map_err(Into::into)); let key = match key { Ok(k) => k, - // Propagate rather than silently dropping: a failure we can't persist - // must not look like a successfully-saved regression. - Err(e) => return Err(e.context("corpus: cannot serialize failing arguments")), + // Propagate rather than silently dropping: an entry we can't persist + // must not look like a successfully-saved one. + Err(e) => return Err(e.context(format!("corpus: cannot serialize {} arguments", what))), }; if seen.insert(key) { existing.push(args.to_vec()); @@ -205,6 +208,17 @@ pub fn append_failure( Ok(()) } +/// Append `args` to the failures file for `(module, test)`, de-duping against +/// the existing entries. Idempotent. +pub fn append_failure( + corpus_dir: &Path, + module_id: &ModuleId, + test_name: &str, + args: &[MoveValue], +) -> Result<()> { + append_entry(corpus_dir, FAILURES_SUBDIR, module_id, test_name, args, "failing") +} + /// Append `args` to the seeds file for `(module, test)`. pub fn append_seed( corpus_dir: &Path, @@ -212,28 +226,7 @@ pub fn append_seed( test_name: &str, args: &[MoveValue], ) -> Result<()> { - let path = corpus_dir - .join(SEEDS_SUBDIR) - .join(corpus_filename(module_id, test_name)); - let mut existing = if path.exists() { - read_corpus_file(&path)? - } else { - Vec::new() - }; - let mut seen: BTreeSet> = existing - .iter() - .filter_map(|e| to_wire(e).ok().and_then(|w| bcs::to_bytes(&w).ok())) - .collect(); - let key = to_wire(args).and_then(|w| bcs::to_bytes(&w).map_err(Into::into)); - let key = match key { - Ok(k) => k, - Err(e) => return Err(e.context("corpus: cannot serialize seed arguments")), - }; - if seen.insert(key) { - existing.push(args.to_vec()); - write_corpus_file(&path, &existing)?; - } - Ok(()) + append_entry(corpus_dir, SEEDS_SUBDIR, module_id, test_name, args, "seed") } /// Standard path resolution. Pass through to expose the layout. diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index 17d3a9cc5fd..9d40f4dd38c 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -251,6 +251,16 @@ fn build_test_info( let spec_ref = match specs.get(var) { Some(s) => s, None => { + // A parameter with no explicit `#[test(...)]` assignment is + // treated as an *implicit fuzz* input over an unrestricted + // domain. This intentionally replaces the legacy compiler's + // hard "Missing test parameter assignment" error: a bare + // `#[test] fun f(a: u64)` now expands into fuzz cases when a + // `FuzzValueSource` is registered (the move-unit-test runner + // installs `DefaultFuzzSource`), and reports a clear "no fuzz + // value source" diagnostic when one is not. This is a + // deliberate behavior change — see the runner-facing docs in + // `tests/unit_test/test/fuzz_implicit.move`. owned_default = ParamSpec::Fuzz { domain: Domain::default(), exclude: Domain::default(), @@ -454,8 +464,9 @@ fn build_test_info( } /// Compact human-readable rendering for a `MoveValue`, used in expanded -/// test-case suffixes like `foo[a=@0x1,b=42]`. -fn format_move_value(v: &MoveValue) -> String { +/// test-case suffixes like `foo[a=@0x1,b=42]`. Also reused by the unit-test +/// runner to render shrink counterexamples, so the two stay in lock-step. +pub fn format_move_value(v: &MoveValue) -> String { match v { MoveValue::Address(a) | MoveValue::Signer(a) => format!("@{}", a.short_str_lossless()), MoveValue::U8(x) => x.to_string(), diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move index b5b406736f7..96b5a716d9c 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.move @@ -12,3 +12,26 @@ module 0x1::M { #[test] public fun bare_zero_args() { } } + +// Implicit fuzzing — intended behavior (read me) +// =============================================== +// A `#[test]` function whose parameters are NOT explicitly assigned (no +// `#[test(a = ..)]`, `a in ..`, or `a != ..`) treats each unassigned parameter +// as an implicit fuzz input over an unrestricted domain. This is a deliberate, +// backwards-incompatible change from the legacy compiler, which rejected such a +// test with a hard "Missing test parameter assignment in test" error. +// +// What you observe depends on whether a `FuzzValueSource` is registered: +// * move-unit-test runner: installs `DefaultFuzzSource`, so each parameter is +// sampled and the test expands into `--fuzz-runs` cases (default 16). A +// bare `#[test] fun f(a: u64)` therefore RUNS rather than failing to build. +// * compiler-only golden tests (this suite): a source is registered, so the +// diagnostics show `fuzz: expanded to N cases`. With no source at all, +// the planner reports a clear "no fuzz value source registered" error +// instead of the old missing-assignment error. +// +// Functions with zero parameters are unaffected: no fuzzing, no error. +// +// Migration note: a pre-existing test that relied on the missing-assignment +// error to flag an under-specified signature will now be fuzzed instead. Assign +// the parameter explicitly (e.g. `#[test(a = 0)]`) to pin it to a fixed value. diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.exp new file mode 100644 index 00000000000..b5ebd0e7580 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.exp @@ -0,0 +1,17 @@ + +Diagnostics: +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_out_of_range.move:6:16 + │ +5 │ #[test(_a != 300)] + │ --------------- fuzz: value 300 is out of range for this integer parameter (max 255) +6 │ public fun exclude_out_of_range(_a: u8) { } + │ ^^^^^^^^^^^^^^^^^^^^ -- Corresponding to this parameter + +error: unable to generate test + ┌─ tests/unit_test/test/fuzz_out_of_range.move:9:16 + │ +8 │ #[test(_a in 250..300)] + │ -------------------- fuzz: range bound 300 is out of range for this integer parameter (max 255) +9 │ public fun range_out_of_range(_a: u8) { } + │ ^^^^^^^^^^^^^^^^^^ -- Corresponding to this parameter diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.move b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.move new file mode 100644 index 00000000000..29d956a24b7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_out_of_range.move @@ -0,0 +1,10 @@ +// Out-of-range fuzz constraints are rejected at plan-build time — the same +// policy applied to concrete `#[test(a = ..)]` values — rather than silently +// wrapped (e.g. `!= 300` on a u8 must NOT become `!= 44`). +module 0x1::M { + #[test(_a != 300)] + public fun exclude_out_of_range(_a: u8) { } + + #[test(_a in 250..300)] + public fun range_out_of_range(_a: u8) { } +} diff --git a/third_party/move/tools/move-unit-test/src/lib.rs b/third_party/move/tools/move-unit-test/src/lib.rs index 650007358ce..2fbd18749cc 100644 --- a/third_party/move/tools/move-unit-test/src/lib.rs +++ b/third_party/move/tools/move-unit-test/src/lib.rs @@ -47,6 +47,14 @@ use test_reporter::UnitTestFactory; /// The default value bounding the amount of gas consumed in a test. const DEFAULT_EXECUTION_BOUND: u64 = 1_000_000; +/// Upper bound on regression cases replayed from the corpus per function. +/// Compile-time fuzz expansion is capped by `MAX_FUZZ_CASES` in the plan +/// builder, but regression cases are appended to the plan *after* planning, so +/// without a ceiling here a corpus that has grown across many CI runs would run +/// an unbounded number of in-process VM executions. When the corpus exceeds +/// this, the most recent entries are replayed and the overflow is reported. +const MAX_REGRESSION_REPLAYS_PER_FN: usize = 256; + #[derive(Debug, Parser, Clone)] #[clap(author, version, about)] pub struct UnitTestingConfig { @@ -247,7 +255,31 @@ impl UnitTestingConfig { let regressions = fuzz_corpus::load_failures(corpus_dir, &module_id, &stem) .unwrap_or_default(); - for (i, args) in regressions.into_iter().enumerate() { + // Bound replays per function. Corpus entries are + // appended in discovery order, so the newest failures + // are at the tail — keep those and skip the oldest + // overflow, reporting what was dropped rather than + // silently truncating. + let skip = regressions + .len() + .saturating_sub(MAX_REGRESSION_REPLAYS_PER_FN); + if skip > 0 { + // Plan assembly runs before any `TestOutput`/diagnostic + // sink exists (the compiler `GlobalEnv` is already + // dropped, and the corpus is unknown to the compiler), + // so stderr is the only channel available here. Keep it + // a single, clearly-prefixed line. + eprintln!( + "warning: fuzz: `{}` has {} saved regression failures; replaying \ + the most recent {} and skipping {} (trim the corpus or raise the \ + replay cap)", + stem, + regressions.len(), + MAX_REGRESSION_REPLAYS_PER_FN, + skip, + ); + } + for (i, args) in regressions.into_iter().enumerate().skip(skip) { let replay_name = format!("{}#regression[{}]", stem, i); module_plan.tests.insert( replay_name.clone(), diff --git a/third_party/move/tools/move-unit-test/src/test_runner.rs b/third_party/move/tools/move-unit-test/src/test_runner.rs index 72470e6faa5..65071a282f6 100644 --- a/third_party/move/tools/move-unit-test/src/test_runner.rs +++ b/third_party/move/tools/move-unit-test/src/test_runner.rs @@ -17,7 +17,7 @@ use legacy_move_compiler::unit_test::{ }; use move_compiler_v2::fuzz::ArgOrigin; use move_binary_format::{ - errors::{Location, VMResult}, + errors::{Location, VMError, VMResult}, file_format::CompiledModule, }; use move_bytecode_utils::Modules; @@ -253,24 +253,25 @@ impl TestOutput<'_, '_, W> { } } -/// Human-readable argument vector used in shrink output. +/// Project a `VMError` onto the `MoveError` identity used to compare failures +/// (status, sub-status, location, message). `MoveError`'s `PartialEq` ignores +/// the message, so two failures are "the same bug" when those first three match. +fn move_error_of(e: &VMError) -> MoveError { + MoveError( + e.major_status(), + e.sub_status(), + e.location().clone(), + e.message().cloned(), + ) +} + +/// Human-readable argument vector used in shrink output. Renders each value +/// through the compiler's `format_move_value` so the shrink counterexample and +/// the expanded-case name (built in the plan builder) format identically. fn format_arguments(args: &[move_core_types::value::MoveValue]) -> String { - use move_core_types::value::MoveValue; let parts: Vec = args .iter() - .map(|v| match v { - MoveValue::Address(a) | MoveValue::Signer(a) => { - format!("@{}", a.short_str_lossless()) - }, - MoveValue::U8(x) => x.to_string(), - MoveValue::U16(x) => x.to_string(), - MoveValue::U32(x) => x.to_string(), - MoveValue::U64(x) => x.to_string(), - MoveValue::U128(x) => x.to_string(), - MoveValue::U256(x) => x.to_string(), - MoveValue::Bool(b) => b.to_string(), - other => format!("{:?}", other), - }) + .map(move_compiler_v2::plan_builder::format_move_value) .collect(); format!("[{}]", parts.join(", ")) } @@ -314,14 +315,21 @@ impl SharedTestingConfig { /// argument vector, or `None` when shrinking is not applicable (no fuzz /// context, no fuzz arguments, or already minimal). /// + /// `original` is the failure being minimized. A shrink candidate is only + /// accepted when it reproduces the *same* failure (same status code, sub + /// status, and abort location) — accepting *any* error would let the + /// shrinker wander onto an unrelated abort (or out-of-gas) and report a + /// "minimal counterexample" that doesn't actually trigger the original bug. + /// /// Bound: 100 total shrink steps per case. Each step tries one shrink per - /// fuzzed argument and accepts the first one that still fails. + /// fuzzed argument and accepts the first one that still reproduces. fn shrink_if_fuzz( &self, test_plan: &ModuleTestPlan, function_name: &str, test_info: &TestCase, factory: &Mutex, + original: &MoveError, ) -> Option> { let ctx = self.fuzz_ctx.as_ref()?; let origins = ctx.metadata.get(&test_plan.module_id, function_name)?; @@ -362,7 +370,9 @@ impl SharedTestingConfig { }; let (_, _, exec_result, _) = self.execute_via_move_vm(test_plan, function_name, &probe, factory); - if exec_result.is_err() { + // Accept only if the candidate reproduces the *same* failure + // (status, sub-status, location — see `move_error_of`). + if matches!(&exec_result, Err(e) if &move_error_of(e) == original) { current = candidate; improved = true; improved_at_least_once = true; @@ -380,6 +390,31 @@ impl SharedTestingConfig { } } + /// Shrink a fuzz failure (if applicable), persist the resulting minimal + /// (or, if shrinking did nothing, original) failing arguments to the + /// regression corpus, and emit the minimal counterexample as a note. A + /// no-op for non-fuzz cases — every step gates on fuzz metadata internally — + /// so it is safe to call from any failure branch. + fn shrink_persist_and_note( + &self, + test_plan: &ModuleTestPlan, + function_name: &str, + test_info: &TestCase, + factory: &Mutex, + original: &MoveError, + output: &TestOutput, + ) { + let shrunk = + self.shrink_if_fuzz(test_plan, function_name, test_info, factory, original); + self.persist_to_corpus(test_plan, function_name, test_info, shrunk.as_deref()); + if let Some(args) = shrunk.as_ref() { + output.note(&format!( + "└─ minimal counterexample: {}", + format_arguments(args) + )); + } + } + #[allow(clippy::field_reassign_with_default)] fn execute_via_move_vm( &self, @@ -505,12 +540,7 @@ impl SharedTestingConfig { match exec_result { Err(err) => { - let actual_err = MoveError( - err.major_status(), - err.sub_status(), - err.location().clone(), - err.message().cloned(), - ); + let actual_err = move_error_of(&err); assert!(err.major_status() != StatusCode::EXECUTED); match test_info.expected_failure.as_ref() { Some(ExpectedFailure::Expected) => { @@ -562,6 +592,16 @@ impl SharedTestingConfig { None if err.major_status() == StatusCode::OUT_OF_GAS => { // Ran out of ticks, report a test timeout and log a test failure output.timeout(function_name); + // A gas blow-up is a real, replayable fuzz finding, so + // persist the failing input so the regression doesn't + // silently vanish next run. We deliberately do NOT + // shrink it: shrinking searches for a *smaller* input + // that still hits OUT_OF_GAS, but smaller inputs almost + // always consume less gas, so each probe is a full + // gas-bounded re-execution that nearly always fails to + // reproduce — up to ~100×args wasted executions for no + // benefit. No-op for non-fuzz cases. + self.persist_to_corpus(test_plan, function_name, test_info, None); stats.test_failure( TestFailure::new( FailureReason::timeout(), @@ -574,28 +614,18 @@ impl SharedTestingConfig { }, None => { output.fail(function_name); - // Topic 3: if this test failure originated from a fuzz-sampled - // case, attempt to shrink it to a minimal counterexample and - // print the result alongside the failure. - let shrunk = self.shrink_if_fuzz( + // Topic 3 + 2: if this failure originated from a + // fuzz-sampled case, shrink it to a minimal + // counterexample (reproducing the *same* error) and + // persist the failing arguments so the next run + // replays them. + self.shrink_persist_and_note( test_plan, function_name, test_info, factory, - ); - if let Some(args) = shrunk.as_ref() { - output.note(&format!( - "└─ minimal counterexample: {}", - format_arguments(args) - )); - } - // Topic 2: persist failing fuzz arguments to the - // regression corpus so the next run replays them. - self.persist_to_corpus( - test_plan, - function_name, - test_info, - shrunk.as_deref(), + &actual_err, + output, ); stats.test_failure( TestFailure::new( From 8bc7af2183bef9d1da8d88e16d9593b9ec4e9633 Mon Sep 17 00:00:00 2001 From: primata Date: Sat, 6 Jun 2026 18:01:02 -0300 Subject: [PATCH 7/9] debloat and raise default to 64 runs --- third_party/move/move-compiler-v2/src/fuzz.rs | 30 +- .../move/move-compiler-v2/src/plan_builder.rs | 280 +++++++++++++++--- .../tests/unit_test/test/fuzz_constraints.exp | 14 +- .../tests/unit_test/test/fuzz_fixtures.exp | 2 +- .../tests/unit_test/test/fuzz_implicit.exp | 4 +- .../tests/unit_test/test/fuzz_primitives.exp | 16 +- .../move/tools/move-unit-test/src/lib.rs | 6 +- .../tools/move-unit-test/tests/fuzz_runner.rs | 26 +- 8 files changed, 313 insertions(+), 65 deletions(-) diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs index 7df62724fb6..56046e49df8 100644 --- a/third_party/move/move-compiler-v2/src/fuzz.rs +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -218,15 +218,29 @@ impl FuzzValueSource for NoFuzzSource { // Configuration // --------------------------------------------------------------------------- +/// Default number of samples drawn per implicit-fuzz `#[test]` parameter. +/// +/// This is the *single source of truth* for the default run count: the +/// [`FuzzConfig::default`] field, the `--fuzz-runs` CLI flag, and the +/// `UnitTestingConfig` default all reference it, so there is exactly one place +/// to change. +/// +/// Set below Foundry's 256 on purpose. Each case is a full in-process MoveVM +/// execution, so the default governs inner-loop `move test` latency; and the +/// plan builder multiplies `runs` against the pairwise expansion of any +/// explicit `#[test]` matrices under the [`MAX_FUZZ_CASES`] cap, so a large +/// default eats the matrix headroom. 64 keeps the inner loop fast while leaving +/// room for matrix+fuzz combinations; raise `--fuzz-runs` (e.g. 256+ in a +/// nightly CI profile) for deeper search. +/// +/// [`MAX_FUZZ_CASES`]: crate::plan_builder +pub const DEFAULT_FUZZ_RUNS: usize = 64; + /// Tunables for [`DefaultFuzzSource`]. The knob *names* mirror Foundry's /// `[fuzz]` section so users coming from EVM tooling find familiar dials, but -/// the defaults are not identical: `runs` defaults to 16 rather than Foundry's -/// 256. The lower default is intentional — each case is a full in-process -/// MoveVM execution, and the plan builder Cartesian-multiplies fuzz `runs` -/// against any explicit `#[test]` matrices under a `MAX_FUZZ_CASES` (1024) cap, -/// so a 256 default would blow that ceiling as soon as a test has a couple of -/// matrix dimensions. Raise `runs` (or `--fuzz-runs`) for deeper search. -/// `dictionary_weight` does match Foundry's default of 40. +/// the defaults are not identical: `runs` defaults to [`DEFAULT_FUZZ_RUNS`] +/// rather than Foundry's 256 (see that constant for why). `dictionary_weight` +/// does match Foundry's default of 40. #[derive(Clone, Debug)] pub struct FuzzConfig { /// Number of samples drawn per implicit-fuzz parameter. @@ -246,7 +260,7 @@ pub struct FuzzConfig { impl Default for FuzzConfig { fn default() -> Self { Self { - runs: 16, + runs: DEFAULT_FUZZ_RUNS, seed: 0, dictionary_weight: 40, max_retry_multiplier: 64, diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index 9d40f4dd38c..59d5f70cbe5 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -34,15 +34,20 @@ use move_model::{ ty::{PrimitiveType, Type}, }; use num::{bigint::Sign, BigInt, ToPrimitive}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; /// Sentinel run count handed to `FuzzValueSource::sample`: `0` means "use the /// source's own configured `runs`" (e.g. `FuzzConfig::runs`, driven by /// `--fuzz-runs`). The planner is generic over the source and has no config of /// its own, so it defers the count to the source rather than hardcoding it. const FUZZ_RUNS_FROM_SOURCE: usize = 0; -/// Cap on Cartesian-product expansion to guard against accidental explosion. -const MAX_FUZZ_CASES: usize = 1024; +/// Cap on test-case expansion to guard against accidental explosion. Applies to +/// the *product* of the pairwise matrix expansion and the fuzz run count, so it +/// must stay comfortably above [`fuzz::DEFAULT_FUZZ_RUNS`] to leave room for +/// matrix+fuzz combinations (2048 / 64 = 32 matrix rows of headroom). +/// +/// [`fuzz::DEFAULT_FUZZ_RUNS`]: crate::fuzz::DEFAULT_FUZZ_RUNS +const MAX_FUZZ_CASES: usize = 2048; //*************************************************************************** // Test Plan Building @@ -316,12 +321,36 @@ fn build_test_info( Some(abort_attribute) => parse_failure_attribute(env, current_module, abort_attribute), }; - // Cartesian over deterministic dimensions; zip across fuzz dimensions. - let det_product: usize = dims + // Pairwise (2-way) covering over deterministic dimensions; zip across fuzz + // dimensions. Explicit matrices used to Cartesian-multiply (`∏ lenᵢ`), which + // bloats combinatorially: three `[1,2,3]` matrices alone were 27 cases. Most + // interaction bugs are 2-way, so we instead generate a pairwise covering + // array — every pair of values across any two matrix params still appears, + // but the case count collapses to roughly the product of the two largest + // dimensions. Pairwise == Cartesian for 0/1/2 matrix params, so this only + // shrinks expansions with three or more. Independent fuzz draws still *zip*: + // `#[test(a, b)]` is N runs binding `a[i]`/`b[i]`, not N² (Foundry's + // `[fuzz] runs = N` semantics). + let det_positions: Vec = dims .iter() - .filter_map(|(_, d)| if let Dim::Det(vs) = d { Some(vs.len()) } else { None }) - .product::() - .max(1); + .enumerate() + .filter_map(|(i, (_, d))| matches!(d, Dim::Det(_)).then_some(i)) + .collect(); + let det_lens: Vec = det_positions + .iter() + .map(|&i| match &dims[i].1 { + Dim::Det(vs) => vs.len(), + Dim::Fuzz { .. } => unreachable!(), + }) + .collect(); + // Each row selects a value-index for every deterministic dim (in + // `det_positions` order); `det_order_of_pos[i]` maps a `dims` position back + // to its column in a row, or `None` for fuzz dims. + let det_rows = pairwise_index_rows(&det_lens); + let mut det_order_of_pos: Vec> = vec![None; dims.len()]; + for (col, &pos) in det_positions.iter().enumerate() { + det_order_of_pos[pos] = Some(col); + } let fuzz_runs: usize = dims .iter() .filter_map(|(_, d)| { @@ -333,7 +362,7 @@ fn build_test_info( }) .min() .unwrap_or(1); - let total = det_product.saturating_mul(fuzz_runs); + let total = det_rows.len().saturating_mul(fuzz_runs); if total > MAX_FUZZ_CASES { env.error( &fn_id_loc, @@ -374,26 +403,22 @@ fn build_test_info( let is_single = total == 1; - // Iterate: for each Cartesian point of the deterministic dims, run `fuzz_runs` zipped - // draws over the fuzz dims. When `had_fuzz` is false this collapses to plain Cartesian. - let det_lens: Vec = dims - .iter() - .map(|(_, d)| match d { - Dim::Det(vs) => vs.len(), - Dim::Fuzz { .. } => 1, // placeholder; we drive fuzz with `fuzz_iter` - }) - .collect(); - + // For each pairwise row over the deterministic dims, run `fuzz_runs` zipped + // draws over the fuzz dims. With no fuzz dims this is just the pairwise rows; + // with no deterministic dims `det_rows` is a single empty row, so it reduces + // to the zipped fuzz draws. let mut cases = Vec::with_capacity(total); - let mut det_indices = vec![0usize; dims.len()]; - loop { + for det_row in &det_rows { for fuzz_iter in 0..fuzz_runs { let mut arguments = Vec::with_capacity(dims.len()); let mut suffix_parts = Vec::with_capacity(dims.len()); let mut origins = Vec::with_capacity(dims.len()); for (i, (var, d)) in dims.iter().enumerate() { let v = match d { - Dim::Det(vs) => &vs[det_indices[i]], + Dim::Det(vs) => { + let col = det_order_of_pos[i].expect("deterministic dim has a column"); + &vs[det_row[col]] + }, Dim::Fuzz { values, .. } => &values[fuzz_iter % values.len()], }; arguments.push(v.clone()); @@ -443,24 +468,131 @@ fn build_test_info( origins, }); } - // Advance odometer across deterministic dims only — fuzz dims are zipped - // by `fuzz_iter` above. - let mut idx = dims.len(); - loop { - if idx == 0 { - return cases; - } - idx -= 1; - if matches!(dims[idx].1, Dim::Fuzz { .. }) { - continue; + } + cases +} + +/// Build a 2-way (pairwise) covering array over deterministic matrix +/// dimensions, returning one row of value-indices per generated test case. +/// +/// Each entry of `lens` is the number of values a dimension can take; the +/// returned rows are index-tuples (`row[k]` selects a value for dimension `k`) +/// such that for *every* pair of dimensions, *every* combination of their +/// values appears in at least one row. This is the default expansion for +/// explicit `#[test]` matrices: most interaction bugs are 2-way, so pairwise +/// preserves that coverage while turning a full Cartesian product (`∏ lenᵢ`) +/// into roughly the product of the two largest dimensions. +/// +/// Degenerate inputs collapse to the exhaustive answer: zero dims yield one +/// empty row, one dim yields one row per value, and two dims yield the full +/// Cartesian product (pairwise *is* Cartesian when there are only two +/// parameters). Implemented with IPOG (In-Parameter-Order, General), which is +/// fully deterministic — no RNG — so expansions are reproducible run to run. +fn pairwise_index_rows(lens: &[usize]) -> Vec> { + // Sentinel for an unassigned ("don't care") slot during construction. + const FREE: usize = usize::MAX; + + if lens.is_empty() { + return vec![Vec::new()]; + } + if lens.iter().any(|&l| l == 0) { + // A zero-length dimension produces no cases at all; callers reject this + // earlier (`Empty matrix []`), but stay defensive rather than index + // out of bounds below. + return Vec::new(); + } + if lens.len() == 1 { + return (0..lens[0]).map(|v| vec![v]).collect(); + } + + // Seed with the full Cartesian product of the first two dimensions — the + // exact pairwise solution for two parameters. + let mut rows: Vec> = Vec::new(); + for a in 0..lens[0] { + for b in 0..lens[1] { + let mut row = vec![FREE; lens.len()]; + row[0] = a; + row[1] = b; + rows.push(row); + } + } + + // Extend one parameter at a time (IPOG horizontal then vertical growth). + for p in 2..lens.len() { + // Pairs still needing coverage between an earlier param `j < p` and `p`, + // encoded as `(j, value_of_j, value_of_p)`. A BTreeSet keeps iteration + // order deterministic. + let mut uncovered: BTreeSet<(usize, usize, usize)> = BTreeSet::new(); + for j in 0..p { + for vj in 0..lens[j] { + for vp in 0..lens[p] { + uncovered.insert((j, vj, vp)); + } } - det_indices[idx] += 1; - if det_indices[idx] < det_lens[idx] { + } + + // Horizontal growth: give each existing row the value for `p` that + // covers the most still-uncovered pairs. + for row in rows.iter_mut() { + if uncovered.is_empty() { break; } - det_indices[idx] = 0; + let mut best_val = 0; + let mut best_gain = -1i64; + for vp in 0..lens[p] { + let gain = (0..p) + .filter(|&j| row[j] != FREE && uncovered.contains(&(j, row[j], vp))) + .count() as i64; + if gain > best_gain { + best_gain = gain; + best_val = vp; + } + } + row[p] = best_val; + for (j, &vj) in row.iter().enumerate().take(p) { + if vj != FREE { + uncovered.remove(&(j, vj, best_val)); + } + } + } + + // Vertical growth: cover the remaining pairs with new rows, merging into + // a row added during this pass whenever both slots are free or already + // agree. + let mut added: Vec> = Vec::new(); + while let Some(&(j, vj, vp)) = uncovered.iter().next() { + uncovered.remove(&(j, vj, vp)); + let mut merged = false; + for row in added.iter_mut() { + let j_ok = row[j] == FREE || row[j] == vj; + let p_ok = row[p] == FREE || row[p] == vp; + if j_ok && p_ok { + row[j] = vj; + row[p] = vp; + merged = true; + break; + } + } + if !merged { + let mut row = vec![FREE; lens.len()]; + row[j] = vj; + row[p] = vp; + added.push(row); + } } + rows.extend(added); } + + // Fill any remaining don't-care slots with a valid value (index 0); every + // required pair is already covered, so this only ever adds coverage. + for row in rows.iter_mut() { + for slot in row.iter_mut() { + if *slot == FREE { + *slot = 0; + } + } + } + rows } /// Compact human-readable rendering for a `MoveValue`, used in expanded @@ -1385,3 +1517,81 @@ fn check_location(env: &GlobalEnv, loc: Loc, attr: &str, location: Option) } location } + +#[cfg(test)] +mod tests { + use super::pairwise_index_rows; + use std::collections::BTreeSet; + + /// Every row must be a valid index-tuple for the given dimension sizes. + fn assert_in_bounds(lens: &[usize], rows: &[Vec]) { + for row in rows { + assert_eq!(row.len(), lens.len()); + for (k, &v) in row.iter().enumerate() { + assert!(v < lens[k], "value {} out of bounds for dim {} (len {})", v, k, lens[k]); + } + } + } + + /// The covering property: for every pair of dimensions, every combination + /// of their values appears in at least one row. + fn assert_pairwise_covered(lens: &[usize], rows: &[Vec]) { + for i in 0..lens.len() { + for j in (i + 1)..lens.len() { + let seen: BTreeSet<(usize, usize)> = + rows.iter().map(|r| (r[i], r[j])).collect(); + assert_eq!( + seen.len(), + lens[i] * lens[j], + "dims ({i},{j}) with lens ({},{}) not fully covered: {} of {}", + lens[i], + lens[j], + seen.len(), + lens[i] * lens[j] + ); + } + } + } + + #[test] + fn degenerate_dimensions() { + assert_eq!(pairwise_index_rows(&[]), vec![Vec::::new()]); + assert_eq!(pairwise_index_rows(&[3]), vec![vec![0], vec![1], vec![2]]); + // A zero-length dimension yields no rows at all. + assert!(pairwise_index_rows(&[2, 0, 3]).is_empty()); + } + + #[test] + fn two_dims_are_full_cartesian() { + let lens = [2usize, 3]; + let rows = pairwise_index_rows(&lens); + assert_eq!(rows.len(), 6); + assert_in_bounds(&lens, &rows); + assert_pairwise_covered(&lens, &rows); + } + + #[test] + fn three_plus_dims_cover_all_pairs_and_shrink() { + // 3^3 = 27 full Cartesian; pairwise must cover every pair yet stay well + // under the product (the pairwise lower bound here is 3*3 = 9). + let lens = [3usize, 3, 3]; + let rows = pairwise_index_rows(&lens); + assert_in_bounds(&lens, &rows); + assert_pairwise_covered(&lens, &rows); + assert!(rows.len() < 27, "expected shrink below full Cartesian, got {}", rows.len()); + assert!(rows.len() >= 9, "cannot cover all pairs with fewer than 9 rows"); + + // Mixed sizes and more dimensions still satisfy the covering property. + for lens in [ + vec![2usize, 3, 4], + vec![4usize, 3, 2, 5], + vec![2usize, 2, 2, 2, 2], + ] { + let rows = pairwise_index_rows(&lens); + assert_in_bounds(&lens, &rows); + assert_pairwise_covered(&lens, &rows); + let full: usize = lens.iter().product(); + assert!(rows.len() <= full); + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp index 64e981b27f6..edef6e92a72 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_constraints.exp @@ -1,42 +1,42 @@ Diagnostics: -note: fuzz: expanded `ne_single` to 16 cases +note: fuzz: expanded `ne_single` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:6:16 │ 6 │ public fun ne_single(_a: signer) { } │ ^^^^^^^^^ -note: fuzz: expanded `ne_list` to 16 cases +note: fuzz: expanded `ne_list` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:9:16 │ 9 │ public fun ne_list(_a: signer) { } │ ^^^^^^^ -note: fuzz: expanded `in_list` to 16 cases +note: fuzz: expanded `in_list` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:12:16 │ 12 │ public fun in_list(_a: signer) { } │ ^^^^^^^ -note: fuzz: expanded `in_inclusive_range` to 16 cases +note: fuzz: expanded `in_inclusive_range` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:15:16 │ 15 │ public fun in_inclusive_range(_a: signer) { } │ ^^^^^^^^^^^^^^^^^^ -note: fuzz: expanded `in_half_open_range` to 16 cases +note: fuzz: expanded `in_half_open_range` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:18:16 │ 18 │ public fun in_half_open_range(_a: signer) { } │ ^^^^^^^^^^^^^^^^^^ -note: fuzz: expanded `in_union` to 16 cases +note: fuzz: expanded `in_union` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:21:16 │ 21 │ public fun in_union(_a: signer) { } │ ^^^^^^^^ -note: fuzz: expanded `in_with_excludes` to 16 cases +note: fuzz: expanded `in_with_excludes` to 64 cases ┌─ tests/unit_test/test/fuzz_constraints.move:26:16 │ 26 │ public fun in_with_excludes(_a: signer) { } diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp index d4ef6630c54..c3a34d7fc1e 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_fixtures.exp @@ -1,6 +1,6 @@ Diagnostics: -note: fuzz: expanded `fuzz_with_fixtures` to 16 cases +note: fuzz: expanded `fuzz_with_fixtures` to 64 cases ┌─ tests/unit_test/test/fuzz_fixtures.move:11:16 │ 11 │ public fun fuzz_with_fixtures(_amount: u64, _recipient: address, _salt: u32) { } diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp index 8d0ff1e1467..a6d4fc028b1 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_implicit.exp @@ -1,12 +1,12 @@ Diagnostics: -note: fuzz: expanded `bare_with_signer` to 16 cases +note: fuzz: expanded `bare_with_signer` to 64 cases ┌─ tests/unit_test/test/fuzz_implicit.move:6:16 │ 6 │ public fun bare_with_signer(_a: signer) { } │ ^^^^^^^^^^^^^^^^ -note: fuzz: expanded `bare_with_two` to 16 cases +note: fuzz: expanded `bare_with_two` to 64 cases ┌─ tests/unit_test/test/fuzz_implicit.move:9:16 │ 9 │ public fun bare_with_two(_a: signer, _b: address) { } diff --git a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp index ee33b483b12..83681753d1f 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/test/fuzz_primitives.exp @@ -1,48 +1,48 @@ Diagnostics: -note: fuzz: expanded `fuzz_u64` to 16 cases +note: fuzz: expanded `fuzz_u64` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:7:16 │ 7 │ public fun fuzz_u64(_a: u64) { } │ ^^^^^^^^ -note: fuzz: expanded `fuzz_u8` to 16 cases +note: fuzz: expanded `fuzz_u8` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:10:16 │ 10 │ public fun fuzz_u8(_a: u8) { } │ ^^^^^^^ -note: fuzz: expanded `fuzz_bool` to 16 cases +note: fuzz: expanded `fuzz_bool` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:13:16 │ 13 │ public fun fuzz_bool(_a: bool) { } │ ^^^^^^^^^ -note: fuzz: expanded `fuzz_address` to 16 cases +note: fuzz: expanded `fuzz_address` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:16:16 │ 16 │ public fun fuzz_address(_a: address) { } │ ^^^^^^^^^^^^ -note: fuzz: expanded `fuzz_pair` to 16 cases +note: fuzz: expanded `fuzz_pair` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:19:16 │ 19 │ public fun fuzz_pair(_a: u64, _b: address) { } │ ^^^^^^^^^ -note: fuzz: expanded `fuzz_range_u64` to 16 cases +note: fuzz: expanded `fuzz_range_u64` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:22:16 │ 22 │ public fun fuzz_range_u64(_a: u64) { } │ ^^^^^^^^^^^^^^ -note: fuzz: expanded `fuzz_exclude_u64` to 16 cases +note: fuzz: expanded `fuzz_exclude_u64` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:25:16 │ 25 │ public fun fuzz_exclude_u64(_a: u64) { } │ ^^^^^^^^^^^^^^^^ -note: fuzz: expanded `fuzz_addr_list` to 16 cases +note: fuzz: expanded `fuzz_addr_list` to 64 cases ┌─ tests/unit_test/test/fuzz_primitives.move:28:16 │ 28 │ public fun fuzz_addr_list(_a: signer) { } diff --git a/third_party/move/tools/move-unit-test/src/lib.rs b/third_party/move/tools/move-unit-test/src/lib.rs index 2fbd18749cc..abb8cf0698a 100644 --- a/third_party/move/tools/move-unit-test/src/lib.rs +++ b/third_party/move/tools/move-unit-test/src/lib.rs @@ -16,7 +16,7 @@ use legacy_move_compiler::{ use move_command_line_common::files::verify_and_create_named_address_mapping; use legacy_move_compiler::unit_test::{ExpectedFailure, TestCase}; use move_compiler_v2::{ - fuzz::{DefaultFuzzSource, FuzzConfig, FuzzPlanMetadata, FuzzValueSource}, + fuzz::{DefaultFuzzSource, FuzzConfig, FuzzPlanMetadata, FuzzValueSource, DEFAULT_FUZZ_RUNS}, fuzz_corpus, plan_builder as plan_builder_v2, }; use std::sync::Arc; @@ -129,7 +129,7 @@ pub struct UnitTestingConfig { pub verbose: bool, /// Number of values to sample per implicit-fuzz `#[test]` parameter. - #[clap(long = "fuzz-runs", default_value_t = 16)] + #[clap(long = "fuzz-runs", default_value_t = DEFAULT_FUZZ_RUNS)] pub fuzz_runs: usize, /// Deterministic seed for the fuzz value source. Defaults to 0; change to @@ -173,7 +173,7 @@ impl Default for UnitTestingConfig { verbose: false, list: false, named_address_values: vec![], - fuzz_runs: 16, + fuzz_runs: DEFAULT_FUZZ_RUNS, fuzz_seed: 0, fuzz_dictionary_weight: 40, fuzz_corpus_dir: None, diff --git a/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs b/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs index 6b102f76de0..e5311bdb5ad 100644 --- a/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs +++ b/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs @@ -44,7 +44,7 @@ fn run(config: &UnitTestingConfig) -> (String, bool, usize) { (String::from_utf8(buffer).unwrap(), ok, total_cases) } -const DEFAULT_FUZZ_RUNS: usize = 16; +use move_compiler_v2::fuzz::DEFAULT_FUZZ_RUNS; /// Implicit-fuzz parameters expand into `DEFAULT_FUZZ_RUNS` *uniquely named* /// cases that all execute without panicking. Before the fix, the decorated @@ -99,3 +99,27 @@ module 0x42::fuzz_mod { assert!(ok, "matrix cases should pass; output:\n{}", output); assert_eq!(output.matches("[ PASS").count(), 3, "output:\n{}", output); } + +/// Multiple explicit matrices expand *pairwise* (2-way covering), not as a full +/// Cartesian product. Three `[_,_,_]` matrices would be 3×3×3 = 27 cases under +/// the old Cartesian expansion; pairwise covers every pair of values across any +/// two parameters in 10 cases. This guards the default-pairwise behavior. +#[test] +fn multi_matrix_expands_pairwise_not_cartesian() { + let (_dir, config) = config_for( + r#" +module 0x42::fuzz_mod { + #[test(_a = [1, 2, 3], _b = [1, 2, 3], _c = [1, 2, 3])] + fun matrix3(_a: u64, _b: u64, _c: u64) { } +} +"#, + ); + let (output, ok, total) = run(&config); + assert_eq!( + total, 10, + "3x3x3 matrices should expand pairwise to 10 cases (27 under full Cartesian); output:\n{}", + output + ); + assert!(ok, "pairwise matrix cases should pass; output:\n{}", output); + assert_eq!(output.matches("[ PASS").count(), 10, "output:\n{}", output); +} From d01e857f4af9f0a4cfa1dd90c1fc3e15af14ba17 Mon Sep 17 00:00:00 2001 From: primata Date: Sat, 6 Jun 2026 19:31:27 -0300 Subject: [PATCH 8/9] fix constants --- third_party/move/move-compiler-v2/src/fuzz.rs | 25 ++++++++++++++++--- .../move/tools/move-unit-test/src/lib.rs | 22 ++++++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs index 56046e49df8..14c3b45efd3 100644 --- a/third_party/move/move-compiler-v2/src/fuzz.rs +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -236,11 +236,28 @@ impl FuzzValueSource for NoFuzzSource { /// [`MAX_FUZZ_CASES`]: crate::plan_builder pub const DEFAULT_FUZZ_RUNS: usize = 64; +/// Default base RNG seed for the fuzz value source. +/// +/// Single source of truth shared by [`FuzzConfig::default`] and the +/// `--fuzz-seed` CLI flag. Deterministic by default (0) so runs reproduce; +/// override to search the space differently across CI runs. +pub const DEFAULT_FUZZ_SEED: u64 = 0; + +/// Default relative weight (0..=100) of dictionary draws against the +/// random+edge strategies. Matches Foundry's `dictionary_weight` of 40. +/// +/// Single source of truth shared by [`FuzzConfig::default`] and the +/// `--fuzz-dictionary-weight` CLI flag. Participates in the +/// `random + edge + dictionary == 100` weighting (with [`EDGE_WEIGHT`]), so the +/// CLI and library defaults must not drift apart. +pub const DEFAULT_FUZZ_DICTIONARY_WEIGHT: u8 = 40; + /// Tunables for [`DefaultFuzzSource`]. The knob *names* mirror Foundry's /// `[fuzz]` section so users coming from EVM tooling find familiar dials, but /// the defaults are not identical: `runs` defaults to [`DEFAULT_FUZZ_RUNS`] -/// rather than Foundry's 256 (see that constant for why). `dictionary_weight` -/// does match Foundry's default of 40. +/// rather than Foundry's 256 (see that constant for why). +/// `dictionary_weight` does match Foundry's default of +/// [`DEFAULT_FUZZ_DICTIONARY_WEIGHT`]. #[derive(Clone, Debug)] pub struct FuzzConfig { /// Number of samples drawn per implicit-fuzz parameter. @@ -261,8 +278,8 @@ impl Default for FuzzConfig { fn default() -> Self { Self { runs: DEFAULT_FUZZ_RUNS, - seed: 0, - dictionary_weight: 40, + seed: DEFAULT_FUZZ_SEED, + dictionary_weight: DEFAULT_FUZZ_DICTIONARY_WEIGHT, max_retry_multiplier: 64, } } diff --git a/third_party/move/tools/move-unit-test/src/lib.rs b/third_party/move/tools/move-unit-test/src/lib.rs index abb8cf0698a..3a74d1db465 100644 --- a/third_party/move/tools/move-unit-test/src/lib.rs +++ b/third_party/move/tools/move-unit-test/src/lib.rs @@ -16,7 +16,10 @@ use legacy_move_compiler::{ use move_command_line_common::files::verify_and_create_named_address_mapping; use legacy_move_compiler::unit_test::{ExpectedFailure, TestCase}; use move_compiler_v2::{ - fuzz::{DefaultFuzzSource, FuzzConfig, FuzzPlanMetadata, FuzzValueSource, DEFAULT_FUZZ_RUNS}, + fuzz::{ + DefaultFuzzSource, FuzzConfig, FuzzPlanMetadata, FuzzValueSource, + DEFAULT_FUZZ_DICTIONARY_WEIGHT, DEFAULT_FUZZ_RUNS, DEFAULT_FUZZ_SEED, + }, fuzz_corpus, plan_builder as plan_builder_v2, }; use std::sync::Arc; @@ -47,6 +50,11 @@ use test_reporter::UnitTestFactory; /// The default value bounding the amount of gas consumed in a test. const DEFAULT_EXECUTION_BOUND: u64 = 1_000_000; +/// Default number of threads used to run tests. Single source of truth shared +/// by the `--threads` CLI default and `UnitTestingConfig::default`, which must +/// agree (the latter is what every programmatic embedder gets). +const DEFAULT_NUM_THREADS: usize = 8; + /// Upper bound on regression cases replayed from the corpus per function. /// Compile-time fuzz expansion is capped by `MAX_FUZZ_CASES` in the plan /// builder, but regression cases are appended to the plan *after* planning, so @@ -69,7 +77,7 @@ pub struct UnitTestingConfig { /// Number of threads to use for running tests. #[clap( name = "num_threads", - default_value_t = 8, + default_value_t = DEFAULT_NUM_THREADS, short = 't', long = "threads" )] @@ -134,13 +142,13 @@ pub struct UnitTestingConfig { /// Deterministic seed for the fuzz value source. Defaults to 0; change to /// search the space differently across CI runs. - #[clap(long = "fuzz-seed", default_value_t = 0)] + #[clap(long = "fuzz-seed", default_value_t = DEFAULT_FUZZ_SEED)] pub fuzz_seed: u64, /// Percentage weight (0..=100) of dictionary draws against random+edge /// draws when fuzzing primitive parameters. Mirrors Foundry's /// `dictionary_weight`. - #[clap(long = "fuzz-dictionary-weight", default_value_t = 40)] + #[clap(long = "fuzz-dictionary-weight", default_value_t = DEFAULT_FUZZ_DICTIONARY_WEIGHT)] pub fuzz_dictionary_weight: u8, /// Directory used as the fuzz corpus. When set, regression cases from @@ -162,7 +170,7 @@ impl Default for UnitTestingConfig { fn default() -> Self { Self { filter: None, - num_threads: 8, + num_threads: DEFAULT_NUM_THREADS, report_statistics: false, report_storage_on_error: false, report_stacktrace_on_abort: false, @@ -174,8 +182,8 @@ impl Default for UnitTestingConfig { list: false, named_address_values: vec![], fuzz_runs: DEFAULT_FUZZ_RUNS, - fuzz_seed: 0, - fuzz_dictionary_weight: 40, + fuzz_seed: DEFAULT_FUZZ_SEED, + fuzz_dictionary_weight: DEFAULT_FUZZ_DICTIONARY_WEIGHT, fuzz_corpus_dir: None, } } From b428708774db079cbc2290d8987f03da41005900 Mon Sep 17 00:00:00 2001 From: primata Date: Wed, 1 Jul 2026 17:56:40 -0400 Subject: [PATCH 9/9] aggregate results --- .../confidential_balance.move | 39 +++ .../sources/account/rate_limiter.move | 63 +++++ .../aggregator/optional_aggregator.move | 50 ++++ .../aptos-framework/sources/storage_gas.move | 40 +++ third_party/move/move-compiler-v2/src/fuzz.rs | 37 ++- .../move/move-compiler-v2/src/plan_builder.rs | 24 +- .../move/tools/move-cli/src/base/test.rs | 55 +++- .../move/tools/move-unit-test/src/lib.rs | 18 +- .../tools/move-unit-test/src/test_runner.rs | 254 +++++++++++++----- .../tools/move-unit-test/tests/fuzz_runner.rs | 56 +++- 10 files changed, 544 insertions(+), 92 deletions(-) diff --git a/aptos-move/framework/aptos-experimental/sources/confidential_asset/confidential_balance.move b/aptos-move/framework/aptos-experimental/sources/confidential_asset/confidential_balance.move index 32e847ce642..941eff93f00 100644 --- a/aptos-move/framework/aptos-experimental/sources/confidential_asset/confidential_balance.move +++ b/aptos-move/framework/aptos-experimental/sources/confidential_asset/confidential_balance.move @@ -383,4 +383,43 @@ module aptos_experimental::confidential_balance { ok } + + // + // Fuzz tests + // + + // `split_into_chunks_u64`/`_u128` decompose an integer into 16-bit limbs and + // lift each limb to a Ristretto `Scalar`. The shift/mask logic + // (`amount >> (i * CHUNK_SIZE_BITS) & 0xffff`) is exactly where an off-by-one + // in the chunk count, the bit width, or the limb ordering slips past + // hand-picked examples. We fuzz the full integer range and check each emitted + // scalar against an independently computed little-endian limb decomposition; + // the assertion only holds if every chunk is the correct 16 bits in the + // correct position, and it covers the high limbs that fixed examples rarely + // reach. + #[test] + fun fuzz_split_into_chunks_u64(amount: u64) { + let chunks = split_into_chunks_u64(amount); + assert!(vector::length(&chunks) == PENDING_BALANCE_CHUNKS, 0); + let i = 0; + while (i < PENDING_BALANCE_CHUNKS) { + let expected = (amount >> ((i * CHUNK_SIZE_BITS) as u8)) & 0xffff; + let expected_scalar = ristretto255::new_scalar_from_u64(expected); + assert!(ristretto255::scalar_equals(vector::borrow(&chunks, i), &expected_scalar), 1); + i = i + 1; + }; + } + + #[test] + fun fuzz_split_into_chunks_u128(amount: u128) { + let chunks = split_into_chunks_u128(amount); + assert!(vector::length(&chunks) == ACTUAL_BALANCE_CHUNKS, 0); + let i = 0; + while (i < ACTUAL_BALANCE_CHUNKS) { + let expected = (amount >> ((i * CHUNK_SIZE_BITS) as u8)) & 0xffff; + let expected_scalar = ristretto255::new_scalar_from_u128(expected); + assert!(ristretto255::scalar_equals(vector::borrow(&chunks, i), &expected_scalar), 1); + i = i + 1; + }; + } } diff --git a/aptos-move/framework/aptos-framework/sources/account/rate_limiter.move b/aptos-move/framework/aptos-framework/sources/account/rate_limiter.move index 68c2ccc9850..9806a1c6ed5 100644 --- a/aptos-move/framework/aptos-framework/sources/account/rate_limiter.move +++ b/aptos-move/framework/aptos-framework/sources/account/rate_limiter.move @@ -169,4 +169,67 @@ module aptos_framework::rate_limiter { refill(&mut bucket); assert!(bucket.current_amount == 10, 603); // Should be full again } + + // + // Fuzz tests + // + + // A token bucket must never hold more than its capacity, no matter how + // requests and time-based refills interleave. `refill`'s arithmetic is where + // a fuzzer earns its keep: a zero `refill_interval` divides by zero, and an + // unbounded `capacity`/elapsed pair overflows `time_passed * capacity` or the + // running `current_amount + new_tokens`. We bound the drawn values into + // realistic ranges so the test exercises the logic rather than tripping the + // u64 guardrails, and assert the capacity invariant plus exact accounting on + // the no-elapsed-time path. + #[test(aptos_framework = @0x1)] + fun fuzz_request_respects_capacity( + aptos_framework: &signer, + cap_raw: u64, + interval_raw: u64, + req_raw: u64, + ) { + timestamp::set_time_has_started_for_testing(aptos_framework); + let capacity = 1 + cap_raw % 1000000; // [1, 1_000_000] + let interval = 1 + interval_raw % 86400; // [1, 86400]; never 0 + let bucket = initialize(capacity, interval); + + // No time has elapsed since initialize(), so the refill inside request() + // adds nothing: a full bucket grants exactly `req` when req <= capacity. + let req = req_raw % (capacity + 1); // [0, capacity] + let granted = request(&mut bucket, req); + assert!(granted, 0); + assert!(bucket.current_amount == capacity - req, 1); + assert!(bucket.current_amount <= bucket.capacity, 2); + } + + #[test(aptos_framework = @0x1)] + fun fuzz_refill_never_exceeds_capacity( + aptos_framework: &signer, + cap_raw: u64, + interval_raw: u64, + elapsed_raw: u64, + ) { + timestamp::set_time_has_started_for_testing(aptos_framework); + let capacity = 1 + cap_raw % 1000000; // [1, 1_000_000] + let interval = 1 + interval_raw % 86400; // [1, 86400] + let bucket = initialize(capacity, interval); + + // Drain fully, advance the clock by a bounded, strictly positive amount + // (update_global_time_for_test requires time to move forward), then + // refill. With capacity <= 1e6 and elapsed <= 1e5, `time_passed * + // capacity` <= 1e11 — well inside u64 — so we test the refill logic, not + // overflow. + assert!(request(&mut bucket, capacity), 0); + assert!(bucket.current_amount == 0, 1); + + let elapsed = 1 + elapsed_raw % 100000; // [1, 100_000] seconds + timestamp::update_global_time_for_test_secs(timestamp::now_seconds() + elapsed); + refill(&mut bucket); + + // A refill tops up to, but never beyond, capacity... + assert!(bucket.current_amount <= bucket.capacity, 2); + // ...and any carried-over fractional accumulation is a proper remainder. + assert!(bucket.fractional_accumulated < interval, 3); + } } diff --git a/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move b/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move index a5d9794862c..f9a982a29d6 100644 --- a/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move +++ b/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move @@ -283,4 +283,54 @@ module aptos_framework::optional_aggregator { destroy(aggregator); } + + // + // Fuzz tests + // + + // `add_integer` aborts unless `value <= limit - current`, and `sub_integer` + // aborts unless `value <= current`. The bug classes worth hunting are an + // off-by-one at the limit boundary and an underflow in the `limit - value` + // headroom computation. We fuzz the limit and both operands independently + // and fold each operand into the always-legal range inside the body, then + // assert the stored value tracks the adds and subs exactly and never exceeds + // the limit. The fold keeps every drawn case on the success path, so the + // assertions — not aborts — are what catch a regression. + #[test] + fun fuzz_integer_add_sub_tracks_value(limit: u128, add_raw: u128, sub_raw: u128) { + let integer = new_integer(limit); + assert!(read_integer(&integer) == 0, 0); + + // `v` in [0, limit]. `limit + 1` would overflow only at limit == MAX_U128, + // where every u128 already satisfies v <= limit. + let v = if (limit == MAX_U128) { add_raw } else { add_raw % (limit + 1) }; + add_integer(&mut integer, v); + assert!(read_integer(&integer) == v, 1); + assert!(read_integer(&integer) <= limit, 2); + + // `s` in [0, v]; same overflow guard against v == MAX_U128. + let s = if (v == MAX_U128) { sub_raw } else { sub_raw % (v + 1) }; + sub_integer(&mut integer, s); + assert!(read_integer(&integer) == v - s, 3); + + destroy_integer(integer); + } + + // Same accounting property exercised end-to-end through the public + // `add`/`sub`/`read` surface on the integer-backed aggregator, whose limit is + // MAX_U128 (so any single u128 operand fits). This covers the option dispatch + // in `add`/`sub`/`read` that the internal test above bypasses. + #[test(account = @aptos_framework)] + fun fuzz_optional_aggregator_roundtrip(account: signer, a: u128, b: u128) { + aggregator_factory::initialize_aggregator_factory(&account); + let aggregator = new(false); + add(&mut aggregator, a); + assert!(read(&aggregator) == a, 0); + + let s = if (a == MAX_U128) { b } else { b % (a + 1) }; + sub(&mut aggregator, s); + assert!(read(&aggregator) == a - s, 1); + + destroy(aggregator); + } } diff --git a/aptos-move/framework/aptos-framework/sources/storage_gas.move b/aptos-move/framework/aptos-framework/sources/storage_gas.move index 991b6192569..4826d5d0fc9 100644 --- a/aptos-move/framework/aptos-framework/sources/storage_gas.move +++ b/aptos-move/framework/aptos-framework/sources/storage_gas.move @@ -619,4 +619,44 @@ module aptos_framework::storage_gas { assert!(gas_parameter.per_byte_read == 1000, 0); }; } + + // + // Fuzz tests + // + + // `interpolate` is integer linear interpolation: + // y0 + (x - x0) * (y1 - y0) / (x1 - x0) + // It is only well-defined when x0 < x1 (else division by zero), x0 <= x <= x1 + // and y0 <= y1 (else u64 underflow in the subtractions), and when the + // intermediate product stays within u64. Fuzz constraints are applied per + // parameter and cannot express these cross-parameter relationships, so we + // draw five unconstrained u64s and fold them into a valid configuration in + // the body. The property under test is the defining one for linear + // interpolation: the output never leaves the [y0, y1] band, and the + // endpoints map exactly. + #[test] + fun fuzz_interpolate_stays_within_bounds( + x0_raw: u64, + span_raw: u64, + frac_raw: u64, + y0_raw: u64, + dy_raw: u64, + ) { + // Keep the x-coordinates in basis-point territory (the only domain + // `interpolate` is ever called with) and the y-values well below the + // overflow threshold: (x - x0) <= 10_000 and (y1 - y0) < 1_000_000_000, so + // the product is at most ~1e13, comfortably inside u64. + let x0 = x0_raw % 10000; + let x1 = x0 + 1 + (span_raw % 10000); // x1 in [x0 + 1, x0 + 10000] + let x = x0 + (frac_raw % (x1 - x0 + 1)); // x in [x0, x1] + let y0 = y0_raw % 1000000000; + let y1 = y0 + (dy_raw % 1000000000); // y1 in [y0, y0 + 1e9 - 1] + + let y = interpolate(x0, x1, y0, y1, x); + assert!(y >= y0, 0); + assert!(y <= y1, 1); + // Endpoints are exact: at x0 the offset is 0, at x1 it is the full (y1 - y0). + assert!(interpolate(x0, x1, y0, y1, x0) == y0, 2); + assert!(interpolate(x0, x1, y0, y1, x1) == y1, 3); + } } diff --git a/third_party/move/move-compiler-v2/src/fuzz.rs b/third_party/move/move-compiler-v2/src/fuzz.rs index 14c3b45efd3..4221c57d0fd 100644 --- a/third_party/move/move-compiler-v2/src/fuzz.rs +++ b/third_party/move/move-compiler-v2/src/fuzz.rs @@ -190,6 +190,14 @@ pub trait FuzzValueSource: Send + Sync { ) -> Option { None } + + /// The base RNG seed this source draws from, when it is seed-driven. + /// Surfaced so the plan builder can label expanded fuzz cases with the seed + /// needed to reproduce them (e.g. `#3[seed=0,amount=28]`). Returns `None` + /// for sources without a reproducible seed. + fn base_seed(&self) -> Option { + None + } } /// Default source that produces no samples and reports a clear error. Plug a @@ -236,13 +244,30 @@ impl FuzzValueSource for NoFuzzSource { /// [`MAX_FUZZ_CASES`]: crate::plan_builder pub const DEFAULT_FUZZ_RUNS: usize = 64; -/// Default base RNG seed for the fuzz value source. +/// Fallback base RNG seed for [`FuzzConfig::default`]. /// -/// Single source of truth shared by [`FuzzConfig::default`] and the -/// `--fuzz-seed` CLI flag. Deterministic by default (0) so runs reproduce; -/// override to search the space differently across CI runs. +/// This is only the *library-level* default used when a `FuzzConfig` is built +/// directly. The unit-test CLI does NOT default `--fuzz-seed` to this: when the +/// flag is omitted, a fresh random seed is drawn per run (see [`random_seed`]) +/// so each run explores a different slice of the input space; pass +/// `--fuzz-seed N` to pin it and reproduce a specific run. pub const DEFAULT_FUZZ_SEED: u64 = 0; +/// Draw a nondeterministic `u64` seed for a fuzz run. Used when the caller did +/// not pin `--fuzz-seed`, so every run searches differently while still being +/// reproducible once the drawn value is logged. +/// +/// Sourced from `RandomState` (OS-seeded, per-instance random) to avoid pulling +/// in the `rand` crate — consistent with this module's no-`rand` policy. Only +/// used to pick a starting seed, never for the value stream itself, which stays +/// the deterministic SplitMix64 in [`Rng`]. +pub fn random_seed() -> u64 { + use std::hash::{BuildHasher, Hasher}; + std::collections::hash_map::RandomState::new() + .build_hasher() + .finish() +} + /// Default relative weight (0..=100) of dictionary draws against the /// random+edge strategies. Matches Foundry's `dictionary_weight` of 40. /// @@ -515,6 +540,10 @@ impl FuzzValueSource for DefaultFuzzSource { let mut rng = Rng(self.config.seed.wrapping_add(seed)); mutate_value(&mut rng, ty, current, domain, exclude, &self.dictionary) } + + fn base_seed(&self) -> Option { + Some(self.config.seed) + } } // --------------------------------------------------------------------------- diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index 59d5f70cbe5..b90d38a7fe3 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -115,13 +115,23 @@ fn construct_module_test_plan( // } let current_module = module.get_name(); - let module_id_for_meta = module.get_identifier().map(|name| { + // Key fuzz metadata by the SAME `ModuleId` that `ModuleTestPlan::new` builds + // (numeric address + the module's name string). Deriving it from + // `module.get_identifier()` instead is a trap: that returns `None` for source + // (non-bytecode) modules, so the plan would still be built from the name + // string while every metadata insert was silently skipped — leaving the + // runner unable to recognize fuzz cases (no seed banner, no shrinking). + let module_id_for_meta = { let addr_bytes = match current_module.addr() { Address::Numerical(num_addr) => Some(*num_addr), Address::Symbolic(sym) => env.resolve_address_alias(*sym), }; - (addr_bytes, name) - }); + let name = Identifier::new(env.symbol_pool().string(current_module.name()).to_string()).ok(); + match (addr_bytes, name) { + (Some(addr), Some(name)) => Some(ModuleId::new(addr, name)), + _ => None, + } + }; let expanded: Vec = module .get_functions() @@ -129,12 +139,8 @@ fn construct_module_test_plan( .collect(); let mut tests: BTreeMap = BTreeMap::new(); for ex in expanded { - if let Some((Some(addr), name)) = module_id_for_meta.as_ref() { - metadata.insert( - ModuleId::new(*addr, name.clone()), - ex.case.test_name.clone(), - ex.origins, - ); + if let Some(module_id) = module_id_for_meta.as_ref() { + metadata.insert(module_id.clone(), ex.case.test_name.clone(), ex.origins); } tests.insert(ex.case.test_name.clone(), ex.case); } diff --git a/third_party/move/tools/move-cli/src/base/test.rs b/third_party/move/tools/move-cli/src/base/test.rs index 71c4f1fd929..838e6945ef1 100644 --- a/third_party/move/tools/move-cli/src/base/test.rs +++ b/third_party/move/tools/move-cli/src/base/test.rs @@ -11,7 +11,10 @@ use legacy_move_compiler::{ unit_test::TestPlan, }; use move_command_line_common::files::{FileHash, MOVE_COVERAGE_MAP_EXTENSION}; -use move_compiler_v2::plan_builder as plan_builder_v2; +use move_compiler_v2::{ + fuzz::{random_seed, DefaultFuzzSource, FuzzConfig, FuzzValueSource}, + plan_builder as plan_builder_v2, +}; use move_core_types::effects::ChangeSet; use move_coverage::coverage_map::{output_map_to_file, CoverageMap}; use move_package::{ @@ -20,7 +23,7 @@ use move_package::{ }; use move_unit_test::{ test_reporter::{UnitTestFactory, UnitTestFactoryWithCostTable}, - UnitTestingConfig, + FuzzRunnerCtx, UnitTestingConfig, }; use move_vm_runtime::tracing::{LOGGING_FILE_WRITER, TRACING_ENABLED}; use move_vm_test_utils::gas_schedule::CostTable; @@ -37,6 +40,7 @@ use std::{ ops::Deref, path::{Path, PathBuf}, process::ExitStatus, + sync::Arc, }; // if not windows nor unix #[cfg(not(any(target_family = "windows", target_family = "unix")))] @@ -221,6 +225,11 @@ pub fn run_move_unit_tests_with_factory = + Arc::new(DefaultFuzzSource::new(&env, fuzz_config)); + let built = plan_builder_v2::construct_test_plan_with_fuzz_source( + &env, + Some(root_package_in_model), + fuzz_source.as_ref(), + ); + // Keep the fuzz metadata/source alongside the plan so the runner can + // shrink failing fuzz cases; `None` (no tests / not compiled) is fine. + let (built_test_plan, fuzz_ctx) = match built { + Some(build) => { + let ctx: Arc = Arc::new(FuzzRunnerCtx { + metadata: build.fuzz_metadata, + source: fuzz_source.clone(), + corpus_dir: None, + }); + (Some(build.plans), Some(ctx)) + }, + None => (None, None), + }; - test_plan = Some((built_test_plan, files.clone(), units.clone())); + test_plan = Some((built_test_plan, fuzz_ctx, files.clone(), units.clone())); Ok((files, units, env)) }, )?; @@ -257,16 +297,17 @@ pub fn run_move_unit_tests_with_factory, /// Percentage weight (0..=100) of dictionary draws against random+edge /// draws when fuzzing primitive parameters. Mirrors Foundry's @@ -182,7 +183,7 @@ impl Default for UnitTestingConfig { list: false, named_address_values: vec![], fuzz_runs: DEFAULT_FUZZ_RUNS, - fuzz_seed: DEFAULT_FUZZ_SEED, + fuzz_seed: None, fuzz_dictionary_weight: DEFAULT_FUZZ_DICTIONARY_WEIGHT, fuzz_corpus_dir: None, } @@ -227,7 +228,8 @@ impl UnitTestingConfig { let (files, units, env) = build_and_report_v2_driver(options).unwrap(); let fuzz_config = FuzzConfig { runs: self.fuzz_runs, - seed: self.fuzz_seed, + // Omitted `--fuzz-seed` => fresh random seed per run. + seed: self.fuzz_seed.unwrap_or_else(random_seed), dictionary_weight: self.fuzz_dictionary_weight, ..FuzzConfig::default() }; diff --git a/third_party/move/tools/move-unit-test/src/test_runner.rs b/third_party/move/tools/move-unit-test/src/test_runner.rs index 65071a282f6..c81dab9c5b2 100644 --- a/third_party/move/tools/move-unit-test/src/test_runner.rs +++ b/third_party/move/tools/move-unit-test/src/test_runner.rs @@ -235,6 +235,20 @@ impl TestOutput<'_, '_, W> { .unwrap() } + /// One-line banner printed at the top of a fuzz batch (all expanded cases of + /// one fuzzed function) carrying the seed needed to reproduce that batch. + fn fuzz_header(&self, fn_name: &str, seed: u64) { + writeln!( + self.writer.lock().unwrap(), + "[ {} ] {}::{} (seed={})", + "FUZZ".bold().bright_cyan(), + format_module_id(&self.test_plan.module_id), + fn_name, + seed + ) + .unwrap() + } + fn timeout(&self, fn_name: &str) { writeln!( self.writer.lock().unwrap(), @@ -246,11 +260,6 @@ impl TestOutput<'_, '_, W> { .unwrap(); } - /// Free-form note printed underneath the last status line. Used by the - /// shrink path to surface the minimal counterexample. - fn note(&self, message: &str) { - writeln!(self.writer.lock().unwrap(), " {}", message).unwrap() - } } /// Project a `VMError` onto the `MoveError` identity used to compare failures @@ -268,18 +277,121 @@ fn move_error_of(e: &VMError) -> MoveError { /// Human-readable argument vector used in shrink output. Renders each value /// through the compiler's `format_move_value` so the shrink counterexample and /// the expanded-case name (built in the plan builder) format identically. -fn format_arguments(args: &[move_core_types::value::MoveValue]) -> String { - let parts: Vec = args - .iter() - .map(move_compiler_v2::plan_builder::format_move_value) - .collect(); - format!("[{}]", parts.join(", ")) +/// Per-case pass/fail classification, computed once per case so the caller can +/// either print it immediately (non-fuzz) or fold it into a [`FuzzBatch`]. +enum CaseStatus { + Pass, + Fail, + Timeout, +} + +/// One fuzzed function's accumulated outcome. A fuzz batch is reported as a +/// single line — every drawn value gathered into a per-parameter array — +/// instead of one line per expanded case. If any draw failed, the batch reports +/// `FAIL` and lists the failing draws; otherwise it reports `PASS` and lists all +/// draws. +struct FuzzBatch { + /// Real function symbol (undecorated), used as the reported name. + function_name: String, + /// `(argument index, parameter name)` for each fuzzed parameter, in argument + /// order. Fixed arguments (e.g. a pinned signer) are excluded. + cols: Vec<(usize, String)>, + /// Formatted fuzzed-argument values, one row per case; each row has one entry + /// per `cols` entry, in `cols` order. + passed: Vec>, + failed: Vec>, +} + +impl FuzzBatch { + fn new(function_name: String, cols: Vec<(usize, String)>) -> Self { + Self { + function_name, + cols, + passed: Vec::new(), + failed: Vec::new(), + } + } + + fn record(&mut self, passed: bool, test_info: &TestCase) { + let row: Vec = self + .cols + .iter() + .map(|(i, _)| { + move_compiler_v2::plan_builder::format_move_value(&test_info.arguments[*i]) + }) + .collect(); + if passed { + self.passed.push(row); + } else { + self.failed.push(row); + } + } + + /// Transpose `rows` over `cols` into a `p0=[v0,v1,..],p1=[..]` suffix. + fn suffix(&self, rows: &[Vec]) -> String { + self.cols + .iter() + .enumerate() + .map(|(c, (_, name))| { + let vals: Vec<&str> = rows.iter().map(|r| r[c].as_str()).collect(); + format!("{}=[{}]", name, vals.join(",")) + }) + .collect::>() + .join(",") + } + + /// Emit the single aggregated status line: `FAIL` listing the failing draws + /// when any case failed, else `PASS` listing every draw. + fn flush(self, output: &TestOutput) { + if self.failed.is_empty() { + let decorated = format!("{}[{}]", self.function_name, self.suffix(&self.passed)); + output.pass(&decorated); + } else { + let decorated = format!("{}[{}]", self.function_name, self.suffix(&self.failed)); + output.fail(&decorated); + } + } } impl SharedTestingConfig { /// Topic 2: write the failing argument vector to the regression corpus /// when a corpus directory is configured. Prefers the shrunk-minimal /// vector when available — that's the cleanest reproducer to persist. + /// The base fuzz seed to advertise for `function_name`, or `None` when the + /// case is not fuzz-origin (fixed matrix/concrete args) or the source has no + /// reproducible seed. `function_name` is the expanded case name, matching how + /// the fuzz metadata is keyed. + fn fuzz_seed_for(&self, test_plan: &ModuleTestPlan, function_name: &str) -> Option { + let ctx = self.fuzz_ctx.as_ref()?; + let origins = ctx.metadata.get(&test_plan.module_id, function_name)?; + if origins.iter().all(|o| matches!(o, ArgOrigin::Fixed)) { + return None; + } + ctx.source.base_seed() + } + + /// The fuzzed argument columns for `function_name`: `(arg_index, param_name)` + /// for each `Fuzz`-origin parameter, in argument order. Fixed arguments (e.g. + /// a pinned signer) are excluded so the aggregated batch line lists only the + /// values that actually varied. `function_name` is the expanded case name, + /// matching how the fuzz metadata is keyed. + fn fuzz_cols(&self, test_plan: &ModuleTestPlan, function_name: &str) -> Vec<(usize, String)> { + let Some(ctx) = self.fuzz_ctx.as_ref() else { + return Vec::new(); + }; + let Some(origins) = ctx.metadata.get(&test_plan.module_id, function_name) else { + return Vec::new(); + }; + origins + .iter() + .enumerate() + .filter_map(|(i, o)| match o { + ArgOrigin::Fuzz { param_name, .. } => Some((i, param_name.clone())), + ArgOrigin::Fixed => None, + }) + .collect() + } + fn persist_to_corpus( &self, test_plan: &ModuleTestPlan, @@ -390,31 +502,6 @@ impl SharedTestingConfig { } } - /// Shrink a fuzz failure (if applicable), persist the resulting minimal - /// (or, if shrinking did nothing, original) failing arguments to the - /// regression corpus, and emit the minimal counterexample as a note. A - /// no-op for non-fuzz cases — every step gates on fuzz metadata internally — - /// so it is safe to call from any failure branch. - fn shrink_persist_and_note( - &self, - test_plan: &ModuleTestPlan, - function_name: &str, - test_info: &TestCase, - factory: &Mutex, - original: &MoveError, - output: &TestOutput, - ) { - let shrunk = - self.shrink_if_fuzz(test_plan, function_name, test_info, factory, original); - self.persist_to_corpus(test_plan, function_name, test_info, shrunk.as_deref()); - if let Some(args) = shrunk.as_ref() { - output.note(&format!( - "└─ minimal counterexample: {}", - format_arguments(args) - )); - } - } - #[allow(clippy::field_reassign_with_default)] fn execute_via_move_vm( &self, @@ -509,7 +596,32 @@ impl SharedTestingConfig { ) -> TestStatistics { let mut stats = TestStatistics::new(); + // Fuzz cases of one function are reported as a single aggregated line + // (every drawn value gathered into per-parameter arrays) rather than one + // line per case. `batch` holds the in-progress fuzz batch: cases of one + // function are contiguous in this `BTreeMap` (keyed by the `fn#idx[..]` + // display name, which shares the function prefix), so we flush on the + // function transition and once more after the loop. Non-fuzz cases keep + // printing one line each. + let mut batch: Option = None; for (function_name, test_info) in &test_plan.tests { + let fuzz_seed = self.fuzz_seed_for(test_plan, function_name); + if batch.as_ref().map(|b| b.function_name.as_str()) + != Some(test_info.function_name.as_str()) + { + if let Some(prev) = batch.take() { + prev.flush(output); + } + if let Some(seed) = fuzz_seed { + // Seed banner once, at the top of the batch. + output.fuzz_header(&test_info.function_name, seed); + batch = Some(FuzzBatch::new( + test_info.function_name.clone(), + self.fuzz_cols(test_plan, function_name), + )); + } + } + let (cs_result, ext_result, exec_result, test_run_info) = self.execute_via_move_vm(test_plan, function_name, test_info, factory); @@ -538,32 +650,34 @@ impl SharedTestingConfig { } }; - match exec_result { + // Classify the case, running the same stats / shrink / corpus side + // effects as before, but defer the printed status so a fuzz batch can + // be collapsed into one line at flush time. + let status = match exec_result { Err(err) => { let actual_err = move_error_of(&err); assert!(err.major_status() != StatusCode::EXECUTED); match test_info.expected_failure.as_ref() { Some(ExpectedFailure::Expected) => { - output.pass(function_name); stats.test_success(test_run_info, test_plan); + CaseStatus::Pass }, Some(ExpectedFailure::ExpectedWithError(expected_err)) if expected_err == &actual_err => { - output.pass(function_name); stats.test_success(test_run_info, test_plan); + CaseStatus::Pass }, Some(ExpectedFailure::ExpectedWithCodeDEPRECATED(code)) if actual_err.0 == StatusCode::ABORTED && actual_err.1.is_some() && actual_err.1.unwrap() == *code => { - output.pass(function_name); stats.test_success(test_run_info, test_plan); + CaseStatus::Pass }, // incorrect cases Some(ExpectedFailure::ExpectedWithError(expected_err)) => { - output.fail(function_name); stats.test_failure( TestFailure::new( FailureReason::wrong_error(expected_err.clone(), actual_err), @@ -572,10 +686,10 @@ impl SharedTestingConfig { save_session_state(), ), test_plan, - ) + ); + CaseStatus::Fail }, Some(ExpectedFailure::ExpectedWithCodeDEPRECATED(expected_code)) => { - output.fail(function_name); stats.test_failure( TestFailure::new( FailureReason::wrong_abort_deprecated( @@ -587,11 +701,10 @@ impl SharedTestingConfig { save_session_state(), ), test_plan, - ) + ); + CaseStatus::Fail }, None if err.major_status() == StatusCode::OUT_OF_GAS => { - // Ran out of ticks, report a test timeout and log a test failure - output.timeout(function_name); // A gas blow-up is a real, replayable fuzz finding, so // persist the failing input so the regression doesn't // silently vanish next run. We deliberately do NOT @@ -599,8 +712,7 @@ impl SharedTestingConfig { // that still hits OUT_OF_GAS, but smaller inputs almost // always consume less gas, so each probe is a full // gas-bounded re-execution that nearly always fails to - // reproduce — up to ~100×args wasted executions for no - // benefit. No-op for non-fuzz cases. + // reproduce. No-op for non-fuzz cases. self.persist_to_corpus(test_plan, function_name, test_info, None); stats.test_failure( TestFailure::new( @@ -610,22 +722,26 @@ impl SharedTestingConfig { save_session_state(), ), test_plan, - ) + ); + CaseStatus::Timeout }, None => { - output.fail(function_name); - // Topic 3 + 2: if this failure originated from a - // fuzz-sampled case, shrink it to a minimal - // counterexample (reproducing the *same* error) and - // persist the failing arguments so the next run - // replays them. - self.shrink_persist_and_note( + // If this failure originated from a fuzz-sampled case, + // shrink it to a minimal counterexample (reproducing the + // *same* error) and persist the failing arguments so the + // next run replays them. No-op for non-fuzz cases. + let shrunk = self.shrink_if_fuzz( test_plan, function_name, test_info, factory, &actual_err, - output, + ); + self.persist_to_corpus( + test_plan, + function_name, + test_info, + shrunk.as_deref(), ); stats.test_failure( TestFailure::new( @@ -635,14 +751,14 @@ impl SharedTestingConfig { save_session_state(), ), test_plan, - ) + ); + CaseStatus::Fail }, } }, Ok(_) => { // Expected the test to fail, but it executed if test_info.expected_failure.is_some() { - output.fail(function_name); stats.test_failure( TestFailure::new( FailureReason::no_error(), @@ -651,16 +767,32 @@ impl SharedTestingConfig { save_session_state(), ), test_plan, - ) + ); + CaseStatus::Fail } else { // Expected the test to execute fully and it did - output.pass(function_name); stats.test_success(test_run_info, test_plan); + CaseStatus::Pass } }, + }; + + match batch.as_mut() { + // Fuzz batch: accumulate; the aggregated line prints at flush. + Some(b) => b.record(matches!(status, CaseStatus::Pass), test_info), + // Non-fuzz: report the case immediately, as before. + None => match status { + CaseStatus::Pass => output.pass(function_name), + CaseStatus::Fail => output.fail(function_name), + CaseStatus::Timeout => output.timeout(function_name), + }, } } + if let Some(prev) = batch.take() { + prev.flush(output); + } + stats } diff --git a/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs b/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs index e5311bdb5ad..efa513ef229 100644 --- a/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs +++ b/third_party/move/tools/move-unit-test/tests/fuzz_runner.rs @@ -64,7 +64,8 @@ module 0x42::fuzz_mod { "#, ); let (output, ok, total) = run(&config); - // Two functions, each kept at the full run count thanks to unique names. + // The plan still expands to one uniquely-named TestCase per draw (this count + // comes from the plan, not the printed lines). assert_eq!( total, 2 * DEFAULT_FUZZ_RUNS, @@ -73,10 +74,59 @@ module 0x42::fuzz_mod { output ); assert!(ok, "all fuzz cases should pass; output:\n{}", output); + // At report time, each fuzzed function collapses to a single aggregated PASS + // line (every draw gathered into per-parameter arrays), preceded by one FUZZ + // seed banner. Two fuzzed functions => 2 of each. assert_eq!( output.matches("[ PASS").count(), - 2 * DEFAULT_FUZZ_RUNS, - "every expanded case should report PASS; output:\n{}", + 2, + "each fuzz fn should report one aggregated PASS line; output:\n{}", + output + ); + assert_eq!( + output.matches("[ FUZZ").count(), + 2, + "each fuzz fn should print one seed banner; output:\n{}", + output + ); +} + +/// A fuzz batch whose cases fail collapses to a single aggregated `[ FAIL ]` +/// line (the failing draws gathered into the array), not one line per case, and +/// still fails the run. Guards the FAIL side of the batch reporting. +#[test] +fn failing_fuzz_batch_reports_single_fail_line() { + let (_dir, config) = config_for( + r#" +module 0x42::fuzz_mod { + #[test] + fun always_aborts(_x: u8) { abort 7 } +} +"#, + ); + let (output, ok, total) = run(&config); + assert_eq!( + total, DEFAULT_FUZZ_RUNS, + "the batch still expands to the full run count; output:\n{}", + output + ); + assert!(!ok, "a failing fuzz batch must fail the run; output:\n{}", output); + assert_eq!( + output.matches("[ FAIL").count(), + 1, + "the whole batch should collapse to one aggregated FAIL line; output:\n{}", + output + ); + assert_eq!( + output.matches("[ PASS").count(), + 0, + "no case passed, so no PASS line; output:\n{}", + output + ); + assert_eq!( + output.matches("[ FUZZ").count(), + 1, + "one seed banner for the batch; output:\n{}", output ); }