Skip to content

Commit 3eb45fa

Browse files
coinage-layer Phase 6 (part 11): coin/entry count_for_handle exec aggregators
Adds two exec aggregators tied to the spec-level count_*_locks_in_vec functions: coin_count_for_handle(handle) -> usize entry_count_for_handle(handle) -> usize Each scans the Vec and returns the number of locks currently referencing `handle`. Sharp postcondition: the returned count exactly equals count_*_locks_in_vec(_, handle, len). Useful for: - Diagnostics ("how many reservations does this in-flight op hold?") - Host-side bulk-sweep termination ("loop releasing until count==0") - Tests that walk an op lifecycle without re-counting in caller code 157 verified, 0 errors.
1 parent 2c254f3 commit 3eb45fa

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

  • rust/crates/coinage-layer/src

rust/crates/coinage-layer/src/lib.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4484,6 +4484,71 @@ impl State {
44844484
vstd::pervasive::unreached()
44854485
}
44864486

4487+
/// Count of coins currently `LockedFor(handle)` across the whole
4488+
/// state. Useful for diagnostics ("how much is reserved by this
4489+
/// in-flight op?") and for callers driving bulk-sweep loops
4490+
/// host-side.
4491+
pub fn coin_count_for_handle(&self, handle: OpHandle) -> (count: usize)
4492+
requires
4493+
self.invariant(),
4494+
ensures
4495+
count as nat == count_coin_locks_in_vec(self.coins@, handle, self.coins@.len() as nat),
4496+
count <= self.coins@.len(),
4497+
{
4498+
let mut c: usize = 0;
4499+
let mut j: usize = 0;
4500+
while j < self.coins.len()
4501+
invariant
4502+
0 <= j <= self.coins.len(),
4503+
c <= j,
4504+
self.invariant(),
4505+
c as nat == count_coin_locks_in_vec(self.coins@, handle, j as nat),
4506+
decreases self.coins.len() - j,
4507+
{
4508+
let is_locked_for = match self.coins[j].state {
4509+
CoinState::LockedFor(h) => h == handle,
4510+
_ => false,
4511+
};
4512+
if is_locked_for {
4513+
c = c + 1;
4514+
}
4515+
j = j + 1;
4516+
}
4517+
c
4518+
}
4519+
4520+
/// Count of entries currently `LocalLockedFor(handle)` across the
4521+
/// whole state. Mirror of `coin_count_for_handle` for the entry
4522+
/// side.
4523+
pub fn entry_count_for_handle(&self, handle: OpHandle) -> (count: usize)
4524+
requires
4525+
self.invariant(),
4526+
ensures
4527+
count as nat == count_entry_locks_in_vec(self.entries@, handle, self.entries@.len() as nat),
4528+
count <= self.entries@.len(),
4529+
{
4530+
let mut c: usize = 0;
4531+
let mut j: usize = 0;
4532+
while j < self.entries.len()
4533+
invariant
4534+
0 <= j <= self.entries.len(),
4535+
c <= j,
4536+
self.invariant(),
4537+
c as nat == count_entry_locks_in_vec(self.entries@, handle, j as nat),
4538+
decreases self.entries.len() - j,
4539+
{
4540+
let is_locked_for = match self.entries[j].local {
4541+
EntryLocal::LocalLockedFor(h) => h == handle,
4542+
_ => false,
4543+
};
4544+
if is_locked_for {
4545+
c = c + 1;
4546+
}
4547+
j = j + 1;
4548+
}
4549+
c
4550+
}
4551+
44874552
/// Count of `Available` coins in purse `p`. Used by maintenance
44884553
/// triggers — e.g. "if coin_count_available(p) > threshold, run
44894554
/// rebalance to consolidate into fewer larger coins".

0 commit comments

Comments
 (0)