Skip to content

Commit

Permalink
voting testcases implementaion
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhishek-1857 committed Oct 4, 2024
1 parent 186cab0 commit 263973a
Show file tree
Hide file tree
Showing 10 changed files with 1,268 additions and 421 deletions.
50 changes: 29 additions & 21 deletions contracts/external/cw4-group/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ pub fn query_member(deps: Deps, addr: Addr, height: Option<u64>) -> StdResult<Me
}
}

// settings for pagination
const MAX_LIMIT: u32 = 30;
const DEFAULT_LIMIT: u32 = 10;

Expand All @@ -237,38 +236,47 @@ pub fn query_list_members(
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<MemberListResponse> {
// Determine the limit, ensuring it's between DEFAULT_LIMIT and MAX_LIMIT
let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;

let mut res_members: Vec<Member> = Vec::new();
let mut res_members: Vec<Member> = Vec::with_capacity(limit); // Pre-allocate capacity

let mut start = start_after.clone(); // Clone start_after to mutate it if necessary

let binding = &MEMBERS_PRIMARY;
let binding = MEMBERS_PRIMARY;
let iter = binding.iter(deps.storage)?;

// Convert `start_after` to Option<&str> for comparison without unnecessary cloning
let mut start_found = start_after.is_none();

for item in iter {
let (address, weight) = item?;
if let Some(start_after) = &start {
if &address == start_after {
// If we found the start point, reset it to start iterating
start = None;

// Skip items until we find the one *after* `start_after`
if let Some(ref start_after_addr) = start_after {
if !start_found {
// Check if the current address matches the start_after value
if &address == start_after_addr {
start_found = true; // We've found the start_after value, start collecting from the next item
}
continue;
}
}
if start.is_none() {
res_members.push(Member {
addr: address.to_string(),
weight,
});
if res_members.len() >= limit {
break; // Break out of loop if limit reached
}

// Once we've found the start or if no `start_after` was provided, collect the items
res_members.push(Member {
addr: address.to_string(),
weight,
});

// Break when we've collected enough members
if res_members.len() >= limit {
break;
}
}

let response = MemberListResponse {
// Return the list of members
Ok(MemberListResponse {
members: res_members,
};

Ok(response)
})
}

pub fn authenticate(deps: Deps, auth: Auth, query_auth: Contract) -> StdResult<Addr> {
Expand Down
141 changes: 97 additions & 44 deletions contracts/external/cw4-group/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ pub const HOOKS: Hooks = Hooks::new("cw4-hooks");
pub const QUERY_AUTH: Item<Contract> = Item::new("query_auth");

/// A historic list of members and total voting weights
pub static MEMBERS_PRIMARY: Keymap<Addr, u64> = Keymap::new(b"staked_balances_primary");
pub static MEMBERS_SNAPSHOT: Keymap<(u64, Addr), u64> = Keymap::new(b"staked_balances_snapshot");
pub static MEMBERS_AT_HEIGHT: Keymap<Addr, Vec<u64>> = Keymap::new(b"user_Staked_at_height");
pub const MEMBERS_PRIMARY: Keymap<Addr, u64> = Keymap::new(b"staked_balances_primary");
pub const MEMBERS_SNAPSHOT: Keymap<(u64, Addr), u64> = Keymap::new(b"staked_balances_snapshot");
pub const MEMBERS_AT_HEIGHT: Keymap<Addr, Vec<u64>> = Keymap::new(b"user_staked_at_height");

pub struct MembersStore {}

impl MembersStore {
// Function to store a value at a specific block height
pub fn save(
Expand All @@ -27,117 +28,169 @@ impl MembersStore {
value: u64,
) -> StdResult<()> {
let default: u64 = 0;

// Load the current primary value, if it exists
let primary = MEMBERS_PRIMARY.get(store, &key.clone());

if primary.is_none() {
// First time staking for this user
MEMBERS_PRIMARY.insert(store, &key.clone(), &value)?;
MEMBERS_SNAPSHOT.insert(store, &(block_height, key.clone()), &default)?;
MEMBERS_AT_HEIGHT.insert(store, &key.clone(), &vec![block_height])?;
} else {
let mut user_staked_height = MEMBERS_AT_HEIGHT.get(store, &key.clone()).unwrap();
// Update staking info for an existing user
let mut user_staked_height = MEMBERS_AT_HEIGHT
.get(store, &key.clone())
.unwrap_or_default();

// Store the old primary value as a snapshot at the current block height
MEMBERS_SNAPSHOT.insert(store, &(block_height, key.clone()), &primary.unwrap())?;
MEMBERS_PRIMARY.insert(store, &key.clone(), &value)?;
user_staked_height.push(block_height);

// Add the new block height to the user's list of heights if it's not a duplicate
if !user_staked_height.contains(&block_height) {
user_staked_height.push(block_height);
}
MEMBERS_AT_HEIGHT.insert(store, &key.clone(), &user_staked_height)?;
}

Ok(())
}

// Function to load the current staking balance of a user
pub fn load(store: &dyn Storage, key: Addr) -> u64 {
MEMBERS_PRIMARY.get(store, &key).unwrap_or_default()
}

// Function to load the staking balance of a user at a specific height
pub fn may_load_at_height(
store: &dyn Storage,
key: Addr,
height: u64,
) -> StdResult<Option<u64>> {
let snapshot_key = (height, key.clone());

let snapshot_value = MEMBERS_SNAPSHOT.get(store, &snapshot_key);
if snapshot_value.is_none() {

// If there's a snapshot at the exact height, return it
if snapshot_value.is_some() {
return Ok(snapshot_value);
}

// Otherwise, get the list of heights this user has staked at
let user_staked_heights = MEMBERS_AT_HEIGHT.get(store, &key).unwrap_or_default();

// If the user has never staked, return the current primary balance
if user_staked_heights.is_empty() {
return Ok(MEMBERS_PRIMARY.get(store, &key));
}

// Find the latest block height before or at the specified height
let index = match user_staked_heights.binary_search(&height) {
Ok(i) => i, // exact match found
Err(i) => i.saturating_sub(1), // closest lower height, handle case where i = 0
};

// If the height is beyond the last checkpoint, return the primary balance
if index == user_staked_heights.len() - 1 {
Ok(MEMBERS_PRIMARY.get(store, &key))
} else {
let x = MEMBERS_AT_HEIGHT.get(store, &key).unwrap();
let id = match x.binary_search(&height) {
Ok(index) => Some(index),
Err(_) => None,
};
// return Ok(Some(Uint128::new(x.len() as u128)));
if id.unwrap() == (x.len() - 1) {
Ok(MEMBERS_PRIMARY.get(store, &key))
} else {
let snapshot_value =
MEMBERS_SNAPSHOT.get(store, &(x[id.unwrap() + 1_usize], key.clone()));
Ok(snapshot_value)
}
// Otherwise, return the snapshot at the closest lower height
let snapshot_height = user_staked_heights[index];
Ok(MEMBERS_SNAPSHOT.get(store, &(snapshot_height, key)))
}
}

// Function to remove a user's staking data
pub fn remove(store: &mut dyn Storage, key: Addr) -> StdResult<()> {
// Remove the member's data from all storage maps
// Get the user's staked heights before removing their data
let user_staked_height = MEMBERS_AT_HEIGHT.get(store, &key).unwrap_or_default();

// Remove the primary and height data
MEMBERS_PRIMARY.remove(store, &key)?;
MEMBERS_AT_HEIGHT.remove(store, &key)?;

// Remove all snapshot entries associated with the member
let user_staked_height = MEMBERS_AT_HEIGHT.get(store, &key).unwrap_or_default();
// Remove all snapshot entries associated with the user
for height in user_staked_height {
MEMBERS_SNAPSHOT.remove(store, &(height, key.clone()))?;
}

// Return Ok(()) if all removals were successful
Ok(())
}
}

/// A historic snapshot of total weight over time
pub const TOTAL_PRIMARY: Item<u64> = Item::new("staked_balances_primary");
pub static TOTAL_SNAPSHOT: Keymap<u64, u64> = Keymap::new(b"staked_balances_snapshot");
pub const TOTAL_AT_HEIGHTS: Item<Vec<u64>> = Item::new("user_Staked_at_height");
pub const TOTAL_SNAPSHOT: Keymap<u64, u64> = Keymap::new(b"staked_balances_snapshot");
pub const TOTAL_AT_HEIGHTS: Item<Vec<u64>> = Item::new("user_staked_at_height");

pub struct TotalStore {}

impl TotalStore {
// Function to store a value at a specific block height
pub fn save(store: &mut dyn Storage, block_height: u64, value: u64) -> StdResult<()> {
let default: u64 = 0;

// Load the current primary value, or default to 0 if not found
let primary = TOTAL_PRIMARY.load(store).unwrap_or_default();

if primary == 0 {
// First time storing total weight
TOTAL_PRIMARY.save(store, &value)?;
TOTAL_SNAPSHOT.insert(store, &block_height, &default)?;
TOTAL_AT_HEIGHTS.save(store, &vec![block_height])?;
} else {
let mut user_staked_height = TOTAL_AT_HEIGHTS.load(store).unwrap_or_default();
// Update total weight for existing entries
let mut staked_heights = TOTAL_AT_HEIGHTS.load(store).unwrap_or_default();

// Insert the old primary value into the snapshot at the current block height
TOTAL_SNAPSHOT.insert(store, &block_height, &primary)?;
TOTAL_PRIMARY.save(store, &value)?;
user_staked_height.push(block_height);
TOTAL_AT_HEIGHTS.save(store, &user_staked_height)?;

// Add the new block height if it's not a duplicate
if !staked_heights.contains(&block_height) {
staked_heights.push(block_height);
}
TOTAL_AT_HEIGHTS.save(store, &staked_heights)?;
}

Ok(())
}

// Function to load the current total staked value
pub fn load(store: &dyn Storage) -> u64 {
TOTAL_PRIMARY.load(store).unwrap_or_default()
}

// Function to load the total staked value at a specific block height
pub fn may_load_at_height(store: &dyn Storage, height: u64) -> StdResult<Option<u64>> {
let snapshot_key = height;
let snapshot_value = TOTAL_SNAPSHOT.get(store, &height);

// If a snapshot exists at the exact height, return it
if snapshot_value.is_some() {
return Ok(snapshot_value);
}

// Otherwise, load all the heights where total staked was recorded
let staked_heights = TOTAL_AT_HEIGHTS.load(store).unwrap_or_default();

let snapshot_value = TOTAL_SNAPSHOT.get(store, &snapshot_key);
if snapshot_value.is_none() {
// If there are no staked heights, return the current total primary value
if staked_heights.is_empty() {
return Ok(Some(TOTAL_PRIMARY.load(store).unwrap_or_default()));
}

// Find the latest block height before or at the specified height
let index = match staked_heights.binary_search(&height) {
Ok(i) => i, // Exact match found
Err(i) => i.saturating_sub(1), // Closest lower height, handle case where i = 0
};

// If the height is beyond the last checkpoint, return the current primary value
if index == staked_heights.len() - 1 {
Ok(Some(TOTAL_PRIMARY.load(store).unwrap_or_default()))
} else {
let x = TOTAL_AT_HEIGHTS.load(store).unwrap_or_default();
let id = match x.binary_search(&height) {
Ok(index) => Some(index),
Err(_) => None,
};
// return Ok(Some(Uint128::new(x.len() as u128)));
if id.unwrap() == (x.len() - 1) {
Ok(Some(TOTAL_PRIMARY.load(store).unwrap_or_default()))
} else {
let snapshot_value = TOTAL_SNAPSHOT.get(store, &(x[id.unwrap() + 1_usize]));
Ok(snapshot_value)
}
// Otherwise, return the snapshot at the closest lower height
let snapshot_height = staked_heights[index];
Ok(TOTAL_SNAPSHOT.get(store, &snapshot_height))
}
}
}
2 changes: 1 addition & 1 deletion contracts/external/snip721-roles/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ pub fn query_list_members(

let mut start = start_after.clone(); // Clone start_after to mutate it if necessary

let binding = &MEMBERS_PRIMARY;
let binding = MEMBERS_PRIMARY;
let iter = binding.iter(deps.storage)?;
for item in iter {
let (address, weight) = item?;
Expand Down
Loading

0 comments on commit 263973a

Please sign in to comment.