store median in Answer struct

This commit is contained in:
De Facto 2021-02-18 11:12:50 +08:00
parent 96a701663e
commit ff0033e540
5 changed files with 47 additions and 36 deletions

View File

@ -37,6 +37,9 @@ pub enum Error {
#[error("No resolve answer")]
NoResolvedAnswer,
#[error("No submitted value")]
NoSubmission,
#[error("Unknown error")]
UnknownError,
}

View File

@ -14,54 +14,22 @@ use borsh_state::InitBorshState;
use solana_program::{
account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized,
};
use state::Aggregator;
use state::{Aggregator, Answer};
#[cfg(not(feature = "no-entrypoint"))]
pub mod entrypoint;
pub struct ResolvedMedian {
pub value: u64,
pub updated_at: u64,
pub created_at: u64,
}
/// Read resolved median value from the aggregator answer submissions
pub fn read_median(
aggregator_info: &AccountInfo,
answer_submissions_info: &AccountInfo,
) -> Result<ResolvedMedian, ProgramError> {
) -> Result<Answer, ProgramError> {
let aggregator = Aggregator::load_initialized(&aggregator_info)?;
if !aggregator.answer.is_initialized() {
return Err(Error::NoResolvedAnswer)?;
}
let submissions = aggregator.answer_submissions(answer_submissions_info)?;
let mut values: Vec<_> = submissions
.data
.iter()
.filter(|s| s.is_initialized())
.map(|s| s.value)
.collect();
// get median value
values.sort();
let median: u64;
let l = values.len();
let i = l / 2;
if l % 2 == 0 {
median = (values[i] + values[i - 1]) / 2;
} else {
median = values[i];
}
Ok(ResolvedMedian {
value: median,
updated_at: aggregator.answer.updated_at,
created_at: aggregator.answer.created_at,
})
Ok(aggregator.answer)
}
// Export current sdk types for downstream users building with a different

View File

@ -258,11 +258,13 @@ impl<'a> SubmitContext<'a> {
answer.created_at = now;
answer.updated_at = now;
answer_submissions.data = round_submissions.data;
} else {
answer.updated_at = now;
answer_submissions.data[i] = new_submission;
}
answer.median = answer_submissions.median()?;
answer_submissions.save(self.answer_submissions)?;
Ok(())
@ -833,6 +835,7 @@ mod tests {
assert_eq!(answer.round_id, 1);
assert_eq!(answer.updated_at, time);
assert_eq!(answer.created_at, time);
assert_eq!(answer.median, 15);
assert_eq!(tt.answer_submission(0)?.value, 10);
assert_eq!(tt.answer_submission(1)?.value, 20);

View File

@ -66,6 +66,40 @@ pub struct Submissions {
// pub data: Vec<Submission>,
}
pub struct ResolvedMedian {
pub value: u64,
pub updated_at: u64,
pub created_at: u64,
}
impl Submissions {
pub fn median(&self) -> Result<u64, ProgramError> {
let mut values: Vec<_> = self.data
.iter()
.filter(|s| s.is_initialized())
.map(|s| s.value)
.collect();
if values.is_empty() {
return Err(Error::NoSubmission)?;
}
// get median value
values.sort();
let median: u64;
let l = values.len();
let i = l / 2;
if l % 2 == 0 {
median = (values[i] + values[i - 1]) / 2;
} else {
median = values[i];
}
Ok(median)
}
}
impl IsInitialized for Submissions {
fn is_initialized(&self) -> bool {
self.is_initialized
@ -84,6 +118,7 @@ pub struct Round {
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
pub struct Answer {
pub round_id: u64,
pub median: u64,
pub created_at: u64,
pub updated_at: u64,
}

View File

@ -161,6 +161,7 @@ class Round extends Serialization {
class Answer extends Serialization {
public round_id!: BN
public median!: BN
public created_at!: BN
public updated_at!: BN
@ -168,6 +169,7 @@ class Answer extends Serialization {
kind: "struct",
fields: [
["round_id", "u64"],
["median", "u64"],
["created_at", "u64"],
["updated_at", "u64"],
],
@ -175,7 +177,7 @@ class Answer extends Serialization {
}
export class Aggregator extends Serialization {
public static size = 189
public static size = 197
public config!: AggregatorConfig
public roundSubmissions!: PublicKey