Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[move] PoF tiebreaker randomize tied bids, maintain fewer seats than bidders #292

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading