Skip to content

Commit

Permalink
[frenemies] use round robin goal assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
sblackshear committed Jan 17, 2023
1 parent fadbb5b commit f6ed4bc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
31 changes: 29 additions & 2 deletions sui_programmability/examples/frenemies/sources/assignment.move
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,24 @@ module frenemies::assignment {
let validators = validator_set::active_validators(sui_system::validators(state));
let len = vector::length(validators);

// derive assignment from the stake of first validator, an address, and the epoch.
// derive vassignment from the stake of first validator, an address, and the epoch.
// this means that a given address will always get the same assignment within an epoch
let top_stake = validator::total_stake(vector::borrow(validators, 0));
let addr = address::to_u256(tx_context::sender(ctx));
let epoch = tx_context::epoch(ctx);
let assignment_seed = addr ^ ((top_stake ^ epoch) as u256);
let validator_idx = assignment_seed % (len as u256);
let validator = validator::sui_address(vector::borrow(validators, (validator_idx as u64)));
let goal = ((assignment_seed % 3) as u8);
let goal = get_goal(addr, epoch);
Assignment { validator, goal, epoch }
}

fun get_goal(addr: u256, epoch: u64): u8 {
// goals are round-robin, but different addresses will start at different points in the round-robin cycle
let offset_epoch = addr + (epoch as u256);
((offset_epoch % 3) as u8)
}

/// Return `FRIEND` if `rank_idx` is in the top third, `NEUTRAL` if `rank_idx` is in the middle third,
/// and `ENEMY` if `rank_idx` is in the bottom third in a system with `num_validators` validators.
/// Note: `rank_idx` is a 0-indexed value, it should always be strictly less than `num_validators`.
Expand Down Expand Up @@ -108,4 +114,25 @@ module frenemies::assignment {
assert!(get_outcome(5, 7) == ENEMY, 0);
assert!(get_outcome(6, 7) == ENEMY, 0);
}

#[test]
fun round_robin_goal() {
// an address should see a cycle of FRIEND, NEUTRAL, ENEMY goals
let addr = address::to_u256(@0x0);
assert!(get_goal(addr, 0) == FRIEND, 0);
assert!(get_goal(addr, 1) == NEUTRAL, 0);
assert!(get_goal(addr, 2) == ENEMY, 0);
assert!(get_goal(addr, 3) == FRIEND, 0);
assert!(get_goal(addr, 4) == NEUTRAL, 0);
assert!(get_goal(addr, 5) == ENEMY, 0);

// different addresses may start in a different place in the cycle
let addr = address::to_u256(@0x1);
assert!(get_goal(addr, 0) == NEUTRAL, 0);
assert!(get_goal(addr, 1) == ENEMY, 0);
assert!(get_goal(addr, 2) == FRIEND, 0);
assert!(get_goal(addr, 3) == NEUTRAL, 0);
assert!(get_goal(addr, 4) == ENEMY, 0);
assert!(get_goal(addr, 5) == FRIEND, 0);
}
}
17 changes: 11 additions & 6 deletions sui_programmability/examples/frenemies/tests/frenemies_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,18 @@ module frenemies::frenemies_tests {

let scenario_val = init_test(copy validators, validators);
let scenario = &mut scenario_val;
// hardcode some assignments for convenience
let v2_scorecard = ts::take_from_address<Scorecard>(scenario, @0x2);
//let v4_scorecard = ts::take_from_address<Scorecard>(scenario, v4);
frenemies::set_assignment_for_testing(&mut v2_scorecard, @0x2, FRIEND, tx_context::epoch(ts::ctx(scenario)));
//frenemies::set_assignment_for_testing(&mut v4_scorecard, @0x4, FRIEND, tx_context::epoch(ts::ctx(scenario)));
ts::return_to_address(@0x2, v2_scorecard);
//ts::return_to_address(@0x4, v4_scorecard);

ts::next_tx(scenario, v2);
{
let scorecard = ts::take_from_sender<Scorecard>(scenario);
let system_state = ts::take_shared<SuiSystemState>(scenario);
// hardcode assignment for convenience
frenemies::set_assignment_for_testing(&mut scorecard, v2, FRIEND, tx_context::epoch(ts::ctx(scenario)));
let coin = coin::mint_for_testing(10, ts::ctx(scenario));
sui_system::request_add_delegation(
&mut system_state, coin, frenemies::validator(&scorecard), ts::ctx(scenario)
Expand Down Expand Up @@ -310,8 +316,8 @@ module frenemies::frenemies_tests {
let scorecard = ts::take_from_sender<Scorecard>(scenario);
let system_state = ts::take_shared<SuiSystemState>(scenario);
let leaderboard = ts::take_shared<Leaderboard>(scenario);
assert!(frenemies::goal(&scorecard) == FRIEND, 0);
assert!(frenemies::validator(&scorecard) == @0x4, 0);
// hardcode assignment for convenience
frenemies::set_assignment_for_testing(&mut scorecard, @0x4, FRIEND, 0);
frenemies::update(&mut scorecard, &mut system_state, &mut leaderboard, ts::ctx(scenario));
// user 4 did not score because their assignment was not met
assert!(frenemies::score(&scorecard) == 0, 0);
Expand All @@ -330,8 +336,7 @@ module frenemies::frenemies_tests {
let scorecard = ts::take_from_sender<Scorecard>(scenario);
let system_state = ts::take_shared<SuiSystemState>(scenario);
let leaderboard = ts::take_shared<Leaderboard>(scenario);
assert!(frenemies::goal(&scorecard) == ENEMY, 0);
assert!(frenemies::validator(&scorecard) == @0x3, 0);
frenemies::set_assignment_for_testing(&mut scorecard, @0x3, ENEMY, 0);
frenemies::update(&mut scorecard, &mut system_state, &mut leaderboard, ts::ctx(scenario));
// user 3 scored
assert!(frenemies::score(&scorecard) == GOAL_COMPLETION_POINTS, 0);
Expand Down

0 comments on commit f6ed4bc

Please sign in to comment.