Skip to content

Commit

Permalink
[move] formal specifications for vouch & burn modules (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jayfromthe13th authored Jan 8, 2025
1 parent 6337cc7 commit 2a310b2
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
53 changes: 53 additions & 0 deletions framework/libra-framework/sources/ol_sources/burn.spec.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
spec ol_framework::burn {
spec module {
pragma verify = true; // Enables verification of the module
pragma aborts_if_is_strict = true; // Ensures strict checking of aborts_if conditions
invariant [suspendable] exists<BurnCounter>(@ol_framework); // Ensures a BurnCounter always exists
}

spec initialize {
pragma aborts_if_is_partial = true; // Allows partial aborts
let addr = signer::address_of(vm);
requires system_addresses::is_ol_framework_address(addr); // Checks if the address is a system address
ensures global<BurnCounter>(@ol_framework).lifetime_recycled == 0; // Ensures lifetime_recycled is initialized to 0
}

spec burn_and_track(coin: Coin<LibraCoin>) {
requires exists<BurnCounter>(@ol_framework); // Requires a BurnCounter to exist
aborts_if !exists<BurnCounter>(@ol_framework); // Aborts if no BurnCounter exists
ensures global<BurnCounter>(@ol_framework).lifetime_burned ==
old(global<BurnCounter>(@ol_framework).lifetime_burned) + coin::value(coin); // Ensures lifetime_burned is incremented by the coin value
pragma aborts_if_is_partial = true; // Allows partial aborts
}

spec set_send_community(sender: &signer, community: bool) {
let addr = signer::address_of(sender);

// No aborts_if conditions needed since function handles both cases
aborts_if false; // Never aborts

// Postconditions
ensures exists<UserBurnPreference>(addr); // Ensures UserBurnPreference exists for the address
ensures global<UserBurnPreference>(addr).send_community == community; // Ensures send_community is set correctly
requires exists<UserBurnPreference>(signer::address_of(sender)); // Ensures UserBurnPreference can be set for the address
}

spec epoch_burn_fees {
pragma aborts_if_is_partial = true; // Allows partial aborts
ensures global<BurnCounter>(@ol_framework).lifetime_burned >= old(global<BurnCounter>(@ol_framework).lifetime_burned); // Ensures lifetime_burned does not decrease
requires global<BurnCounter>(@ol_framework).lifetime_burned < MAX_U64; // Requires lifetime_burned to be less than MAX_U64
}

spec vm_migration {
pragma aborts_if_is_partial = true; // Allows partial aborts
}

spec vm_burn_with_user_preference {
pragma aborts_if_is_partial = true; // Allows partial aborts
}

spec BurnCounter {
invariant lifetime_burned <= MAX_U64; // Ensures lifetime_burned does not exceed MAX_U64
invariant lifetime_recycled <= MAX_U64; // Ensures lifetime_recycled does not exceed MAX_U64
}
}
81 changes: 81 additions & 0 deletions framework/libra-framework/sources/ol_sources/vouch.spec.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
spec ol_framework::vouch {
spec module {
pragma verify = true; // Enables verification of the module
}

// Specification for identifying true friends of a given address
spec true_friends(addr: address): vector<address> {
pragma aborts_if_is_partial = true; // Allows partial aborts

// Basic vector property
ensures vector::length(result) >= 0; // Ensures the result is a valid vector

// If there are no vouches, result should be empty
ensures !exists<ReceivedVouches>(addr) ==>
vector::length(result) == 0; // Ensures result is empty if no vouches exist

// If we have vouches, they must be in a valid state
ensures exists<ReceivedVouches>(addr) ==>
vector::length(global<ReceivedVouches>(addr).incoming_vouches) >= 0; // Ensures vouches are valid if they exist

// If result is non-empty, we must have vouches
ensures vector::length(result) > 0 ==>
exists<ReceivedVouches>(addr); // Ensures vouches exist if result is non-empty
}

// Specification for revoking a vouch
spec revoke {
pragma aborts_if_is_partial = true; // Allows partial aborts

// Basic property - function should not abort
aborts_if false; // Never aborts

// After revoke, vouches vector should be valid
ensures forall addr: address where exists<ReceivedVouches>(addr):
vector::length(global<ReceivedVouches>(addr).incoming_vouches) >= 0; // Ensures vouches are valid after revoke

// After revoke, the number of vouches should decrease or stay the same
ensures forall addr: address where exists<ReceivedVouches>(addr):
vector::length(global<ReceivedVouches>(addr).incoming_vouches) <=
old(vector::length(global<ReceivedVouches>(addr).incoming_vouches)); // Ensures vouches do not increase after revoke
}

// Specification for checking non-expired vouches
spec all_not_expired(addr: address): vector<address> {
pragma aborts_if_is_partial = true; // Allows partial aborts

// Basic vector property - result must be a valid vector
ensures vector::length(result) >= 0; // Ensures the result is a valid vector

// If we have vouches, they must be in a valid state
ensures exists<ReceivedVouches>(addr) ==>
vector::length(global<ReceivedVouches>(addr).incoming_vouches) >= 0; // Ensures vouches are valid if they exist
}

// Specification for bulk setting vouch records
spec bulk_set(val: address, buddy_list: vector<address>) {
pragma aborts_if_is_partial = true; // Allows partial aborts

// Function should not abort
aborts_if false; // Never aborts

// If ReceivedVouches doesn't exist, nothing changes
ensures !exists<ReceivedVouches>(val) ==> true; // No change if vouches do not exist

// If ReceivedVouches exists, ensure basic properties
ensures exists<ReceivedVouches>(val) ==> {
let post = global<ReceivedVouches>(val);
// Length of incoming_vouches must be less than or equal to buddy_list
vector::length(post.incoming_vouches) <= vector::length(buddy_list) // Ensures vouches do not exceed buddy list
};

// Ensures the state is modified
modifies global<ReceivedVouches>(val); // Indicates that vouches are modified
}

// Add a helper function to make specifications more readable
spec fun is_subset_of_buddy_list(addr_vec: vector<address>, buddy_list: vector<address>): bool {
forall i in 0..vector::length(addr_vec):
exists j in 0..vector::length(buddy_list): addr_vec[i] == buddy_list[j] // Checks if addr_vec is a subset of buddy_list
}
}

0 comments on commit 2a310b2

Please sign in to comment.