Skip to content

Commit

Permalink
Fix payable outcomes (#30)
Browse files Browse the repository at this point in the history
* add permutation of entry winners and fix to one winning score
  • Loading branch information
tee8z authored Oct 6, 2024
1 parent 7d2a65d commit 9b2b18e
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 363 deletions.
53 changes: 46 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion daemon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "daemon"
version = "1.1.0"
version = "1.2.0"
edition = "2021"
repository = "https://github.com/tee8z/noaa-data-pipeline"

Expand Down
3 changes: 2 additions & 1 deletion oracle/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "oracle"
version = "1.1.0"
version = "1.2.0"
edition = "2021"
repository = "https://github.com/tee8z/noaa-data-pipeline"

Expand Down Expand Up @@ -34,6 +34,7 @@ num_cpus = "1.16.0"
openssl = { version = "0.10.60", features = ["vendored"] }
pem-rfc7468 = { version = "0.7.0", features = ["alloc"] }
rand = "0.8.5"
rayon = "1.8"
regex = "1.10.3"
rustix = "0.38.19"
scooby = "0.5.0"
Expand Down
6 changes: 3 additions & 3 deletions oracle/src/db/event_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,15 +351,15 @@ impl EventData {
.flat_map(|(a, b, c, d, e)| {
let temp_low = match c {
Some(c) => Value::Text(c.to_string()),
None => Value::Null,
_ => Value::Null,
};
let temp_high = match d {
Some(d) => Value::Text(d.to_string()),
None => Value::Null,
_ => Value::Null,
};
let wind_speed = match e {
Some(e) => Value::Text(e.to_string()),
None => Value::Null,
_ => Value::Null,
};
vec![
Value::Text(a.to_string()),
Expand Down
51 changes: 9 additions & 42 deletions oracle/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use dlctix::EventAnnouncement;
use duckdb::arrow::datatypes::ToByteSlice;
use duckdb::types::{OrderedMap, ToSqlOutput, Type, Value};
use duckdb::{ffi, ErrorCode, Row, ToSql};
use itertools::Itertools;
use log::{debug, info};
use serde::{Deserialize, Serialize};
use time::format_description::well_known::Rfc3339;
Expand All @@ -18,9 +17,12 @@ use uuid::Uuid;

pub mod event_data;
pub mod event_db_migrations;
pub mod outcome_generator;
pub mod weather_data;

pub use event_data::*;
pub use event_db_migrations::*;
pub use outcome_generator::*;
pub use weather_data::{Forecast, Observation, Station, WeatherData};

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
Expand All @@ -39,8 +41,6 @@ pub struct CreateEvent {
pub number_of_values_per_entry: usize,
/// Total number of allowed entries into the event
pub total_allowed_entries: usize,
/// Total amount of places that are part of the winnings split
pub number_of_places_win: usize,
/// Add a coordinator that will use the event entries in a competition
pub coordinator: Option<CoordinatorInfo>,
}
Expand All @@ -53,16 +53,14 @@ pub struct CreateEventMessage {
/// Time at which the attestation will be added to the event, needs to be after the observation date
pub signing_date: OffsetDateTime,
#[serde(with = "time::serde::rfc3339")]
/// Date of when the weather observations occured (midnight UTC), all entries must be made before this time
/// Date of when the weather observations occurred (midnight UTC), all entries must be made before this time
pub observation_date: OffsetDateTime,
/// NOAA observation stations used in this event
pub locations: Vec<String>,
/// The number of values that can be selected per entry in the event (default to number_of_locations * 3, (temp_low, temp_high, wind_speed))
pub number_of_values_per_entry: usize,
/// Total number of allowed entries into the event
pub total_allowed_entries: usize,
/// Total amount of places that are part of the winnings split
pub number_of_places_win: usize,
}

impl CreateEventMessage {
Expand All @@ -82,7 +80,6 @@ impl From<CreateEvent> for CreateEventMessage {
locations: value.locations,
number_of_values_per_entry: value.number_of_values_per_entry,
total_allowed_entries: value.total_allowed_entries,
number_of_places_win: value.number_of_places_win,
}
}
}
Expand Down Expand Up @@ -134,41 +131,11 @@ impl CreateEventData {
event.observation_date.format(&Rfc3339).unwrap()
));
}
let possible_user_outcomes: Vec<Vec<usize>> =
generate_winner_permutations(event.total_allowed_entries);
info!("user outcomes: {:?}", possible_user_outcomes);

// number_of_values_per_entry * 2 == max value, create array from max value to 0
// determine all possible messages that we might sign
let max_number_of_points_per_value_in_entry = 2;
let possible_scores: Vec<i64> = (0..=(event.number_of_values_per_entry
* max_number_of_points_per_value_in_entry))
.map(|val| val as i64)
.collect();

// allows us to have comps where say the top 3 scores split the pot
let possible_outcome_rankings: Vec<Vec<i64>> = possible_scores
.iter()
.combinations(event.number_of_places_win)
//Sort possible combinations in desc order
.map(|mut combos| {
combos.sort_by_key(|n| i64::MAX - *n);
combos
})
.filter(|combination| {
// Check if the combination is sorted in descending order, if not filter out of possible outcomes
combination.windows(2).all(|window| window[0] >= window[1])
})
.map(|combination| combination.into_iter().cloned().collect())
.collect();
info!("outcomes: {:?}", possible_outcome_rankings);
// holds all possible scoring results of the event
let outcome_messages: Vec<Vec<u8>> = possible_outcome_rankings
.into_iter()
.map(|inner_vec| {
inner_vec
.into_iter()
.flat_map(|num| num.to_be_bytes())
.collect::<Vec<u8>>()
})
.collect();
let outcome_messages: Vec<Vec<u8>> = generate_outcome_messages(possible_user_outcomes);

let mut rng = rand::thread_rng();
let nonce = Scalar::random(&mut rng);
Expand All @@ -193,7 +160,7 @@ impl CreateEventData {
signing_date: event.signing_date,
nonce,
total_allowed_entries: event.total_allowed_entries as i64,
number_of_places_win: event.number_of_places_win as i64,
number_of_places_win: 1_i64, // Default to 1 winning score to simplify possible outcomes
number_of_values_per_entry: event.number_of_values_per_entry as i64,
locations: event.clone().locations,
event_annoucement,
Expand Down
54 changes: 54 additions & 0 deletions oracle/src/db/outcome_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use itertools::Itertools;
use rayon::prelude::*;

pub fn generate_winner_permutations(num_players: usize) -> Vec<Vec<usize>> {
(0..=num_players)
.into_par_iter()
.flat_map(|r| {
(0..num_players)
.combinations(r)
.map(|v| v.into_iter().collect::<Vec<_>>())
.collect::<Vec<_>>()
})
.collect()
}

pub fn generate_outcome_messages(possible_user_outcomes: Vec<Vec<usize>>) -> Vec<Vec<u8>> {
possible_user_outcomes
.into_iter()
.map(|inner_vec| {
inner_vec
.into_iter()
.flat_map(|num| num.to_be_bytes())
.collect::<Vec<u8>>()
})
.collect()
}

#[cfg(test)]
mod test {

use super::generate_winner_permutations;

#[test]
fn can_generate_list_of_winners_small() {
let num_players = 5;
let permutations: Vec<Vec<usize>> = generate_winner_permutations(num_players);
println!("permutations: {:?}", permutations);
assert_eq!(permutations.len(), 32);
}

#[test]
fn can_generate_list_of_winners_default_size() {
let num_players = 20;
let permutations: Vec<Vec<usize>> = generate_winner_permutations(num_players);
assert_eq!(permutations.len(), 1_048_576);
}

#[test]
fn can_generate_list_of_winners_large() {
let num_players = 25;
let permutations: Vec<Vec<usize>> = generate_winner_permutations(num_players);
assert_eq!(permutations.len(), 33_554_432);
}
}
Loading

0 comments on commit 9b2b18e

Please sign in to comment.