Skip to content

Commit

Permalink
[move] PoF tiebreaker randomize tied bids, maintain fewer seats than …
Browse files Browse the repository at this point in the history
…bidders (replay PR)[breaking] (0LNetworkCommunity#299)
  • Loading branch information
soaresa authored and 0o-de-lally committed Aug 17, 2024
1 parent 87493b7 commit cc1050c
Show file tree
Hide file tree
Showing 27 changed files with 2,452 additions and 1,674 deletions.
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generated by Cargo
# will have compiled files and executables
/target/
**/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Expand All @@ -24,4 +24,8 @@ sccache.log
*.bpl

# exclude diem dependency
diem/
diem/

# exclude move coverage
.coverage_map.mvcov
.trace
30 changes: 16 additions & 14 deletions framework/cached-packages/src/libra_framework_sdk_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type Bytes = Vec<u8>;
/// }
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))]
#[cfg_attr(feature = "fuzzing", proptest(no_params))]
pub enum EntryFunctionCall {
/// Offers rotation capability on behalf of `account` to the account at address `recipient_address`.
/// An account can delegate its rotation capability to only one other address at one time. If the account
Expand Down Expand Up @@ -93,14 +95,14 @@ pub enum EntryFunctionCall {
/// Generic authentication key rotation function that allows the user to rotate their authentication key from any scheme to any scheme.
/// To authorize the rotation, we need two signatures:
/// - the first signature `cap_rotate_key` refers to the signature by the account owner's current key on a valid `RotationProofChallenge`,
/// demonstrating that the user intends to and has the capability to rotate the authentication key of this account;
/// demonstrating that the user intends to and has the capability to rotate the authentication key of this account;
/// - the second signature `cap_update_table` refers to the signature by the new key (that the account owner wants to rotate to) on a
/// valid `RotationProofChallenge`, demonstrating that the user owns the new private key, and has the authority to update the
/// `OriginatingAddress` map with the new address mapping `<new_address, originating_address>`.
/// To verify these two signatures, we need their corresponding public key and public key scheme: we use `from_scheme` and `from_public_key_bytes`
/// to verify `cap_rotate_key`, and `to_scheme` and `to_public_key_bytes` to verify `cap_update_table`.
/// A scheme of 0 refers to an Ed25519 key and a scheme of 1 refers to Multi-Ed25519 keys.
/// `originating address` refers to an account's original/first address.
/// valid `RotationProofChallenge`, demonstrating that the user owns the new private key, and has the authority to update the
/// `OriginatingAddress` map with the new address mapping `<new_address, originating_address>`.
/// To verify these two signatures, we need their corresponding public key and public key scheme: we use `from_scheme` and `from_public_key_bytes`
/// to verify `cap_rotate_key`, and `to_scheme` and `to_public_key_bytes` to verify `cap_update_table`.
/// A scheme of 0 refers to an Ed25519 key and a scheme of 1 refers to Multi-Ed25519 keys.
/// `originating address` refers to an account's original/first address.
///
/// Here is an example attack if we don't ask for the second signature `cap_update_table`:
/// Alice has rotated her account `addr_a` to `new_addr_a`. As a result, the following entry is created, to help Alice when recovering her wallet:
Expand Down Expand Up @@ -1027,14 +1029,14 @@ pub fn account_revoke_signer_capability(
/// Generic authentication key rotation function that allows the user to rotate their authentication key from any scheme to any scheme.
/// To authorize the rotation, we need two signatures:
/// - the first signature `cap_rotate_key` refers to the signature by the account owner's current key on a valid `RotationProofChallenge`,
/// demonstrating that the user intends to and has the capability to rotate the authentication key of this account;
/// demonstrating that the user intends to and has the capability to rotate the authentication key of this account;
/// - the second signature `cap_update_table` refers to the signature by the new key (that the account owner wants to rotate to) on a
/// valid `RotationProofChallenge`, demonstrating that the user owns the new private key, and has the authority to update the
/// `OriginatingAddress` map with the new address mapping `<new_address, originating_address>`.
/// To verify these two signatures, we need their corresponding public key and public key scheme: we use `from_scheme` and `from_public_key_bytes`
/// to verify `cap_rotate_key`, and `to_scheme` and `to_public_key_bytes` to verify `cap_update_table`.
/// A scheme of 0 refers to an Ed25519 key and a scheme of 1 refers to Multi-Ed25519 keys.
/// `originating address` refers to an account's original/first address.
/// valid `RotationProofChallenge`, demonstrating that the user owns the new private key, and has the authority to update the
/// `OriginatingAddress` map with the new address mapping `<new_address, originating_address>`.
/// To verify these two signatures, we need their corresponding public key and public key scheme: we use `from_scheme` and `from_public_key_bytes`
/// to verify `cap_rotate_key`, and `to_scheme` and `to_public_key_bytes` to verify `cap_update_table`.
/// A scheme of 0 refers to an Ed25519 key and a scheme of 1 refers to Multi-Ed25519 keys.
/// `originating address` refers to an account's original/first address.
///
/// Here is an example attack if we don't ask for the second signature `cap_update_table`:
/// Alice has rotated her account `addr_a` to `new_addr_a`. As a result, the following entry is created, to help Alice when recovering her wallet:
Expand Down
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
2 changes: 2 additions & 0 deletions framework/libra-framework/sources/genesis.move
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module diem_framework::genesis {
use diem_framework::transaction_fee;
use diem_framework::transaction_validation;
use diem_framework::version;
use diem_framework::randomness;

//////// 0L ////////
use diem_framework::validator_universe;
Expand Down Expand Up @@ -137,6 +138,7 @@ module diem_framework::genesis {
reconfiguration::initialize(&diem_framework_account);
block::initialize(&diem_framework_account, epoch_interval_microsecs);
state_storage::initialize(&diem_framework_account);
randomness::initialize(&diem_framework_account);

//////// 0L ////////

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);
}
}
2 changes: 1 addition & 1 deletion framework/libra-framework/sources/ol_sources/ancestry.move
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ module ol_framework::ancestry {

// now loop through all the accounts again, and check if this target
// account is related to anyone.
let k = 0;
let k = 0;
while (k < vector::length<address>(&list)) {
let comparison_acc = vector::borrow(&list, k);
// skip if you're the same person
Expand Down
Loading

0 comments on commit cc1050c

Please sign in to comment.