Skip to content

Commit

Permalink
critical tests for ol_account, slow, sacred, written and passing
Browse files Browse the repository at this point in the history
  • Loading branch information
0o-de-lally committed Nov 10, 2023
1 parent 679b67a commit 92018e5
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 54 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/formal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ jobs:
# Move framework tests
# TODO:
- name: move framework
working-directory: ./framework/libra-framework
run: ${{github.workspace}}/diem move prove -f guid
- name: prover tests
working-directory: ./framework
run: make prove
13 changes: 11 additions & 2 deletions framework/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# Prover Tests are WIP
# These are the prover tests that have been written
# and are known to pass
PROVER_TESTS = demo ol_account slow sacred

test:
cargo r upgrade --output-dir ./releases/upgrade --framework-local-dir ./libra-framework
VENDOR_TESTS = chain_id guid

prove:
@cd libra-framework && \
for i in ${PROVER_TESTS} ${VENDOR_TESTS}; do \
diem move prove -f $$i; \
done
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ spec diem_framework::coin {
coin: Coin<CoinType>;
let coin_store = global<CoinStore<CoinType>>(account_addr);
aborts_if !exists<CoinStore<CoinType>>(account_addr);
aborts_if coin_store.frozen;
// aborts_if coin_store.frozen;
}

/// The value of `zero_coin` must be 0.
Expand Down Expand Up @@ -276,8 +276,8 @@ spec diem_framework::coin {

aborts_if !exists<CoinStore<CoinType>>(account_addr_from);
aborts_if !exists<CoinStore<CoinType>>(to);
aborts_if coin_store_from.frozen;
aborts_if coin_store_to.frozen;
// aborts_if coin_store_from.frozen;
// aborts_if coin_store_to.frozen;
aborts_if coin_store_from.coin.value < amount;

ensures account_addr_from != to ==> coin_store_post_from.coin.value ==
Expand Down Expand Up @@ -307,7 +307,7 @@ spec diem_framework::coin {
let coin_store = global<CoinStore<CoinType>>(account_addr);
let balance = coin_store.coin.value;
aborts_if !exists<CoinStore<CoinType>>(account_addr);
aborts_if coin_store.frozen;
// aborts_if coin_store.frozen;
aborts_if balance < amount;
}

Expand Down
51 changes: 14 additions & 37 deletions framework/libra-framework/sources/ol_sources/demo.spec.move
Original file line number Diff line number Diff line change
@@ -1,46 +1,23 @@
spec ol_framework::demo {
spec module {
pragma verify = true;
pragma aborts_if_is_strict;
}

// spec set_version(account: &signer, major: u64) {
// use std::signer;
// use diem_framework::chain_status;
// use diem_framework::timestamp;
// use diem_framework::stake;
// use diem_framework::coin::CoinInfo;
// use diem_framework::gas_coin::GasCoin;
// use diem_framework::transaction_fee;
// // use diem_framework::staking_config;
// // Not verified when verify_duration_estimate > vc_timeout
// pragma verify_duration_estimate = 120; // TODO: set because of timeout (property proved).
// include transaction_fee::RequiresCollectedFeesPerValueLeqBlockDiemSupply;
// // include staking_config::StakingRewardsConfigRequirement;
// requires chain_status::is_operating();
// requires timestamp::spec_now_microseconds() >= reconfiguration::last_reconfiguration_time();
// requires exists<stake::ValidatorFees>(@diem_framework);
// requires exists<CoinInfo<GasCoin>>(@diem_framework);

// aborts_if !exists<SetVersionCapability>(signer::address_of(account));
// aborts_if !exists<Version>(@diem_framework);

// let old_major = global<Version>(@diem_framework).major;
// aborts_if !(old_major < major);
// }
spec print_this(account: &signer) {
// should not abort
pragma aborts_if_is_strict;
}

// /// Abort if resource already exists in `@diem_framwork` when initializing.
// spec initialize(diem_framework: &signer, initial_version: u64) {
// use std::signer;
// TODO in strict mode
spec set_message(account: &signer, message: string::String) {
// pragma aborts_if_is_strict;
// let events = borrow_global<MessageHolder>(signer::address_of(account)).message_change_events;
// aborts_if event::counter(events) > MAX_U64;
}

// aborts_if signer::address_of(diem_framework) != @diem_framework;
// aborts_if exists<Version>(@diem_framework);
// aborts_if exists<SetVersionCapability>(@diem_framework);
// }
spec get_message(addr: address): string::String {
pragma aborts_if_is_strict;
aborts_if !exists<MessageHolder>(addr);

// /// This module turns on `aborts_if_is_strict`, so need to add spec for test function `initialize_for_test`.
// spec initialize_for_test {
// // Don't verify test functions.
// pragma verify = false;
// }
}
}
9 changes: 7 additions & 2 deletions framework/libra-framework/sources/ol_sources/libra_coin.move
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ module ol_framework::gas_coin {
}

/// Can only called during genesis to initialize the Diem coin.
public(friend) fun initialize(diem_framework: &signer) {
public(friend) fun initialize(diem_framework: &signer) acquires FinalMint {
system_addresses::assert_diem_framework(diem_framework);

let (burn_cap, freeze_cap, mint_cap) = coin::initialize_with_parallelizable_supply<LibraCoin>(
Expand All @@ -179,6 +179,8 @@ module ol_framework::gas_coin {

coin::destroy_freeze_cap(freeze_cap);
coin::destroy_burn_cap(burn_cap);

genesis_set_final_supply(diem_framework, 1000)
}

/// FOR TESTS ONLY
Expand Down Expand Up @@ -260,10 +262,13 @@ module ol_framework::gas_coin {
/// get the gas coin supply. Helper which wraps coin::supply and extracts option type
// NOTE: there is casting between u128 and u64, but 0L has final supply below the u64.
public fun supply(): u64 {

let supply_opt = coin::supply<LibraCoin>();
if (option::is_some(&supply_opt)) {
let value = *option::borrow(&supply_opt);
assert!(value <= MAX_U64, ESUPPLY_OVERFLOW);
spec {
assume value < MAX_U64;
};
return (value as u64)
};
0
Expand Down
26 changes: 25 additions & 1 deletion framework/libra-framework/sources/ol_sources/ol_account.move
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module ol_framework::ol_account {
use diem_framework::coin::{Self, Coin};
use diem_framework::event::{EventHandle, emit_event};
use diem_framework::system_addresses;
use diem_framework::chain_status;
use std::error;
use std::signer;
use std::option::{Self, Option};
Expand Down Expand Up @@ -41,6 +42,15 @@ module ol_framework::ol_account {
/// On legacy account migration we need to check if we rotated auth keys correctly and can find the user address.
const ECANT_MATCH_ADDRESS_IN_LOOKUP: u64 = 7;

/// trying to transfer zero coins
const EZERO_TRANSFER: u64 = 8;

/// why is VM trying to use this?
const ENOT_FOR_VM: u64 = 9;





struct BurnTracker has key {
prev_supply: u64,
Expand Down Expand Up @@ -189,9 +199,19 @@ module ol_framework::ol_account {
/// Withdraw funds while respecting the transfer limits
public fun withdraw(sender: &signer, amount: u64): Coin<GasCoin> acquires
BurnTracker {
spec {
assume !system_addresses::signer_is_ol_root(sender);
assume chain_status::is_operating();
};
// never abort when its a system address
// if (system_addresses::signer_is_ol_root(sender)) return
// coin::zero<GasCoin>(); // and VM needs to figure this out.

let addr = signer::address_of(sender);
assert!(amount > 0, error::invalid_argument(EZERO_TRANSFER));

let limit = slow_wallet::unlocked_amount(addr);
assert!(amount < limit, error::invalid_state(EINSUFFICIENT_BALANCE));
assert!(amount <= limit, error::invalid_state(EINSUFFICIENT_BALANCE));
slow_wallet::maybe_track_unlocked_withdraw(addr, amount);
let coin = coin::withdraw<GasCoin>(sender, amount);
// the outgoing coins should trigger an update on this account
Expand Down Expand Up @@ -365,6 +385,10 @@ module ol_framework::ol_account {
// only track when the attributable is > 1. Otherwise the
// whole chain of updates will be incorrect
if (attributed_burn > 0) {
spec {
assume (state.burn_at_last_calc + attributed_burn) < MAX_U64;
};

state.cumu_burn = state.burn_at_last_calc + attributed_burn;
// now change last calc
state.burn_at_last_calc = attributed_burn;
Expand Down
33 changes: 29 additions & 4 deletions framework/libra-framework/sources/ol_sources/ol_account.spec.move
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
spec ol_framework::ol_account {
spec module {
pragma verify = true;
pragma aborts_if_is_strict;
// pragma aborts_if_is_strict;
invariant [suspendable] chain_status::is_operating() ==> exists<gas_coin::FinalMint>(@diem_framework);
invariant [suspendable] chain_status::is_operating() ==> exists<coin::CoinInfo<GasCoin>>(@diem_framework);

}

// /// Check if the bytes of the auth_key is 32.
Expand All @@ -26,9 +29,31 @@ spec ol_framework::ol_account {
len(authentication_key) != 32
}

// spec transfer(source: &signer, to: address, amount: u64) {
// pragma verify = false;
// }
// ol_account::withdraw can never use more than the slow wallet limit
spec withdraw(sender: &signer, amount: u64): Coin<GasCoin>{
include AssumeCoinRegistered;

let account_addr = signer::address_of(sender);
aborts_if amount == 0;

let coin_store = global<coin::CoinStore<GasCoin>>(account_addr);
let balance = coin_store.coin.value;

aborts_if balance < amount;

// in the case of slow wallets
let slow_store = global<slow_wallet::SlowWallet>(account_addr);
aborts_if exists<slow_wallet::SlowWallet>(account_addr) &&
slow_store.unlocked < amount;

ensures result == Coin<GasCoin>{value: amount};
}

spec schema AssumeCoinRegistered {
sender: &signer;
let account_addr = signer::address_of(sender);
aborts_if !coin::is_account_registered<GasCoin>(account_addr);
}

spec assert_account_exists(addr: address) {
aborts_if !account::exists_at(addr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,16 @@ module ol_framework::slow_wallet {
maybe_track_unlocked_deposit(recipient, amount);
}
/// if a user spends/transfers unlocked coins we need to track that spend
public(friend) fun maybe_track_unlocked_withdraw(payer: address, amount: u64) acquires SlowWallet {
public(friend) fun maybe_track_unlocked_withdraw(payer: address, amount:
u64) acquires SlowWallet {

if (!exists<SlowWallet>(payer)) return;
let s = borrow_global_mut<SlowWallet>(payer);

spec {
assume s.transferred + amount < MAX_U64;
};

s.transferred = s.transferred + amount;

// THE VM is able to overdraw an account's unlocked amount.
Expand Down

0 comments on commit 92018e5

Please sign in to comment.