Skip to content

Commit

Permalink
creates address_utils module to host bubble sort algorithm and shuffl…
Browse files Browse the repository at this point in the history
…e duplicates
  • Loading branch information
soaresa committed Jul 21, 2024
1 parent 2486b78 commit f19bff1
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 284 deletions.
32 changes: 11 additions & 21 deletions framework/drop-user-tools/jail_with_gc.move
Original file line number Diff line number Diff line change
Expand Up @@ -160,31 +160,21 @@ module ol_framework::jail {
};
}

/// gets a list of validators based on their jail reputation
/// Sort validators based on their jail reputation
/// this is used in the bidding process for Proof-of-Fee where
/// we seat the validators with the least amount of consecutive failures
/// to rejoin.
public(friend) fun sort_by_jail(vec_address: vector<address>): vector<address> acquires Jail {

// Sorting the accounts vector based on value (weights).
// Bubble sort algorithm
let length = vector::length(&vec_address);

let i = 0;
while (i < length){
let j = 0;
while(j < length-i-1){

let (_, value_j) = get_jail_reputation(*vector::borrow(&vec_address, j));
let (_, value_jp1) = get_jail_reputation(*vector::borrow(&vec_address, j + 1));

if(value_j > value_jp1){
vector::swap<address>(&mut vec_address, j, j+1);
};
j = j + 1;
};
i = i + 1;
};
// get the reputation of the validators
let reputation = vector::map(vec_address, |addr| {
let (_, value) = get_jail_reputation(addr);
value
});

// sort the validators based on their reputation
address_utils::sort_by_values(&mut vec_address, &mut reputation);
// shuffle duplicates scores to ensure fairness
address_utils::shuffle_duplicates(&mut vec_address, &reputation);

vec_address
}
Expand Down
229 changes: 229 additions & 0 deletions framework/libra-framework/sources/ol_sources/address_utils.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/// This module provides utility functions for handling and manipulating vectors of
/// addresses and their corresponding values.

module ol_framework::address_utils {
use std::error;
use std::vector;
use diem_framework::randomness;

// Error code for different length of addresses and values
const EDIFFERENT_LENGTH: u64 = 1;

// A, B, C, easy as 1, 2, 3

// Bubble sort addresses and corresponding values
public fun sort_by_values(addresses: &mut vector<address>, values: &mut vector<u64>) {
assert!(vector::length(addresses) == vector::length(values), error::invalid_argument(EDIFFERENT_LENGTH));
let len = vector::length<u64>(values);
let i = 0;
while (i < len) {
let j = 0;
while (j < len - i - 1) {
let value_j = *vector::borrow<u64>(values, j);
let value_jp1 = *vector::borrow<u64>(values, j + 1);
if (value_j > value_jp1) {
vector::swap<u64>(values, j, j + 1);
vector::swap<address>(addresses, j, j + 1);
};
j = j + 1;
};
i = i + 1;
};
}

// Shuffle addresses with the same values to ensure randomness position
public fun shuffle_duplicates(addresses: &mut vector<address>, values: &vector<u64>) {
assert!(vector::length(addresses) == vector::length(values), error::invalid_argument(EDIFFERENT_LENGTH));
let len = vector::length(values);
let i = 0;
while (i < len) {
let j = i + 1;
while (j < len && *vector::borrow(values, i) == *vector::borrow(values, j)) {
j = j + 1;
};
if (j > i + 1) {
let slice_len = j - i;
let perm = randomness::permutation(slice_len);
let temp_addresses = vector::empty<address>();
let k = 0;
while (k < slice_len) {
let pos = i + k;
vector::push_back(&mut temp_addresses, *vector::borrow(addresses, pos));
k = k + 1;
};
k = 0;
while (k < slice_len) {
let perm_pos = *vector::borrow(&perm, k);
*vector::borrow_mut(addresses, i + k) = *vector::borrow(&temp_addresses, perm_pos);
k = k + 1;
};
};
i = j;
};
}

// Bubble Sort tests

#[test]
#[expected_failure(abort_code = 0x10001, location = ol_framework::address_utils)]
fun test_sort_by_values_different_lengths() {
let values = vector[1, 2, 3];
let addresses = vector[@0x1, @0x2];
// This should trigger an assertion error due to different lengths
sort_by_values(&mut addresses, &mut values);
}

#[test]
fun test_sort_empty_vectors() {
let values: vector<u64> = vector::empty();
let addresses: vector<address> = vector::empty();
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[], 10002);
assert!(addresses == vector[], 10003);
}

#[test]
fun test_sort_single_element() {
let values = vector[10];
let addresses = vector[@0x1];
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[10], 10004);
assert!(addresses == vector[@0x1], 10005);
}

#[test]
fun test_sort_already_sorted() {
let values = vector[1, 2, 3, 4, 5];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[1, 2, 3, 4, 5], 10006);
assert!(addresses == vector[@0x1, @0x2, @0x3, @0x4, @0x5], 10007);
}

#[test]
fun test_sort_reverse_order() {
let values = vector[5, 4, 3, 2, 1];
let addresses = vector[@0x5, @0x4, @0x3, @0x2, @0x1];
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[1, 2, 3, 4, 5], 10008);
assert!(addresses == vector[@0x1, @0x2, @0x3, @0x4, @0x5], 10009);
}

#[test]
fun test_sort_with_duplicates() {
let values = vector[4, 2, 2, 3, 1];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[1, 2, 2, 3, 4], 10010);
assert!(addresses == vector[@0x5, @0x2, @0x3, @0x4, @0x1], 10011);
}

#[test]
fun test_sort_random_order() {
let values = vector[3, 1, 4, 5, 2];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[1, 2, 3, 4, 5], 10012);
assert!(addresses == vector[@0x2, @0x5, @0x1, @0x3, @0x4], 10013);
}

#[test]
fun test_sort_all_elements_equal() {
let values = vector[3, 3, 3, 3, 3];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
sort_by_values(&mut addresses, &mut values);
assert!(values == vector[3, 3, 3, 3, 3], 10014);
assert!(addresses == vector[@0x1, @0x2, @0x3, @0x4, @0x5], 10015);
}


// Shuffle Tests

#[test]
#[expected_failure(abort_code = 0x10001, location = ol_framework::address_utils)]
fun test_shuffle_duplicates_different_lengths() {
let values = vector[1, 2, 3];
let addresses = vector[@0x1, @0x2];
// This should trigger an assertion error due to different lengths
shuffle_duplicates(&mut addresses, &mut values);
}

#[test]
fun test_shuffle_no_duplicates() {
// No duplicates in the values vector
let values = vector[1, 2, 3, 4, 5];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
shuffle_duplicates(&mut addresses, &mut values);
assert!(values == vector[1, 2, 3, 4, 5], 10017);
assert!(addresses == vector[@0x1, @0x2, @0x3, @0x4, @0x5], 10018);
}

#[test(root = @ol_framework)]
fun test_shuffle_with_duplicates(root: &signer) {
// One group of duplicates in the values vector
randomness::initialize_for_testing(root);
let values = vector[1, 2, 2, 3, 4];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
let original_addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5];
let shuffled = false;
let i = 0;

while (i < 10) {
shuffle_duplicates(&mut addresses, &mut values);
if (addresses != original_addresses) {
shuffled = true;
break
};
i = i + 1;
};

assert!(values == vector[1, 2, 2, 3, 4], 10019);
assert!(shuffled, 10020);
}

#[test(root = @ol_framework)]
fun test_shuffle_multiple_duplicate_groups(root: &signer) {
// Multiple groups of duplicates in the values vector
randomness::initialize_for_testing(root);
let values = vector[1, 2, 2, 3, 3, 4];
let addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5, @0x6];
let original_addresses = vector[@0x1, @0x2, @0x3, @0x4, @0x5, @0x6];
let shuffled = false;
let i = 0;

while (i < 10) {
shuffle_duplicates(&mut addresses, &mut values);
if (addresses != original_addresses) {
shuffled = true;
break
};
i = i + 1;
};

assert!(values == vector[1, 2, 2, 3, 3, 4], 10021);
assert!(shuffled, 10022);
}

#[test(root = @ol_framework)]
fun test_shuffle_all_elements_equal(root: &signer) {
// All elements in the values vector are the same
randomness::initialize_for_testing(root);
let values = vector[2, 2, 2, 2];
let addresses = vector[@0x1, @0x2, @0x3, @0x4];
let original_addresses = vector[@0x1, @0x2, @0x3, @0x4];
let shuffled = false;
let i = 0;

while (i < 10) {
shuffle_duplicates(&mut addresses, &mut values);
if (addresses != original_addresses) {
shuffled = true;
break
};
i = i + 1;
};

assert!(values == vector[2, 2, 2, 2], 10023);
assert!(shuffled, 10024);
}
}
33 changes: 12 additions & 21 deletions framework/libra-framework/sources/ol_sources/jail.move
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module ol_framework::jail {
use std::error;
use ol_framework::vouch;
use ol_framework::stake;
use ol_framework::address_utils;

friend ol_framework::validator_universe;
friend ol_framework::epoch_boundary;
Expand Down Expand Up @@ -157,31 +158,21 @@ module ol_framework::jail {
};
}

/// gets a list of validators based on their jail reputation
/// Sort validators based on their jail reputation
/// this is used in the bidding process for Proof-of-Fee where
/// we seat the validators with the least amount of consecutive failures
/// to rejoin.
public(friend) fun sort_by_jail(vec_address: vector<address>): vector<address> acquires Jail {

// Sorting the accounts vector based on value (weights).
// Bubble sort algorithm
let length = vector::length(&vec_address);

let i = 0;
while (i < length){
let j = 0;
while(j < length-i-1){

let (_, value_j) = get_jail_reputation(*vector::borrow(&vec_address, j));
let (_, value_jp1) = get_jail_reputation(*vector::borrow(&vec_address, j + 1));

if(value_j > value_jp1){
vector::swap<address>(&mut vec_address, j, j+1);
};
j = j + 1;
};
i = i + 1;
};
// get the reputation of the validators
let reputation = vector::map(vec_address, |addr| {
let (_, value) = get_jail_reputation(addr);
value
});

// sort the validators based on their reputation
address_utils::sort_by_values(&mut vec_address, &mut reputation);
// shuffle duplicates scores to ensure fairness
address_utils::shuffle_duplicates(&mut vec_address, &reputation);

vec_address
}
Expand Down
Loading

0 comments on commit f19bff1

Please sign in to comment.