-
Notifications
You must be signed in to change notification settings - Fork 114
feat(oracle): WIP add scores account #407
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
base: main
Are you sure you want to change the base?
Changes from 3 commits
b343951
1561e80
b58625c
18c6787
32c577e
2ec0004
a02a10b
0c98527
87f61ec
2f6f359
2697cb2
d07a256
98a6a52
4260e2e
6c9d3e6
8e00103
aa1e0a7
2372be6
63352ec
aaa12bf
e2aa645
2169e8d
de0f7c3
4396054
0563db6
6c321bf
9e90897
5c1f750
02f6257
7800412
9b52a40
a18ec0c
5932402
21c38c8
413abc3
23a1da8
1a11ca4
1fa4c6a
dd453fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
use { | ||
super::{ | ||
AccountHeader, | ||
PythAccount, | ||
}, | ||
crate::c_oracle_header::{ | ||
PC_ACCTYPE_SCORE, | ||
PC_MAX_PUBLISHERS, | ||
PC_MAX_SYMBOLS, | ||
PC_MAX_SYMBOLS_64, | ||
}, | ||
bytemuck::{ | ||
Pod, | ||
Zeroable, | ||
}, | ||
solana_program::{ | ||
program_error::ProgramError, | ||
pubkey::Pubkey, | ||
}, | ||
std::cmp::max, | ||
}; | ||
|
||
#[repr(C)] | ||
#[derive(Copy, Clone)] | ||
pub struct PublisherScoresAccount { | ||
pub header: AccountHeader, | ||
pub num_publishers: usize, | ||
pub num_symbols: usize, | ||
// a constant used to normalize the scores | ||
pub z: u32, | ||
|
||
// array[x][y] is a u64 whose bits represent if publisher x publishes symbols 64*y to 64*(y+1) - 1 | ||
pub publisher_permissions: [[u64; PC_MAX_SYMBOLS_64 as usize]; PC_MAX_PUBLISHERS as usize], | ||
pub scores: [f64; PC_MAX_PUBLISHERS as usize], | ||
keyvankhademi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pub publishers: [Pubkey; PC_MAX_PUBLISHERS as usize], | ||
pub symbols: [Pubkey; PC_MAX_SYMBOLS as usize], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We actually already have something similar to this (a list of all symbols) in the mapping account but the product accounts (and not the price accounts) are listed there |
||
} | ||
|
||
impl PublisherScoresAccount { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This struct is begging for a prop test like in this https://github.com/pyth-network/pyth-client/blob/main/program/rust/src/tests/test_twap.rs#L50 |
||
fn get_publisher_permission(&self, x: usize, y: usize) -> bool { | ||
(self.publisher_permissions[x][y / 64] >> (y % 64)) & 1 == 1 | ||
} | ||
|
||
fn set_publisher_permission(&mut self, x: usize, y: usize, value: bool) { | ||
if value { | ||
self.publisher_permissions[x][y / 64] |= 1 << (y % 64); | ||
} else { | ||
self.publisher_permissions[x][y / 64] &= !(1 << (y % 64)); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will try this at some point to see how much it will change the program size, my current guess is that it will increase it. |
||
} | ||
|
||
pub fn add_publisher( | ||
&mut self, | ||
publisher: Pubkey, | ||
price_account: Pubkey, | ||
) -> Result<(), ProgramError> { | ||
let publisher_index = self | ||
.publishers | ||
.iter() | ||
.position(|&x| x == publisher) | ||
.unwrap_or(self.num_publishers); | ||
|
||
if publisher_index == self.num_publishers { | ||
if self.num_publishers == PC_MAX_PUBLISHERS as usize { | ||
return Err(ProgramError::AccountDataTooSmall); | ||
} | ||
|
||
self.publishers[self.num_publishers] = publisher; | ||
self.num_publishers += 1; | ||
} | ||
|
||
let symbol_index = self | ||
.symbols | ||
.iter() | ||
.position(|&x| x == price_account) | ||
.ok_or(ProgramError::InvalidArgument)?; | ||
|
||
self.set_publisher_permission(publisher_index, symbol_index, true); | ||
self.calculate_scores() | ||
} | ||
|
||
pub fn del_publisher( | ||
&mut self, | ||
publisher: Pubkey, | ||
price_account: Pubkey, | ||
) -> Result<(), ProgramError> { | ||
let publisher_index = self | ||
.publishers | ||
.iter() | ||
.position(|&x| x == publisher) | ||
.ok_or(ProgramError::InvalidArgument)?; | ||
|
||
let symbol_index = self | ||
.symbols | ||
.iter() | ||
.position(|&x| x == price_account) | ||
.ok_or(ProgramError::InvalidArgument)?; | ||
|
||
self.set_publisher_permission(publisher_index, symbol_index, false); | ||
self.calculate_scores() | ||
} | ||
|
||
pub fn add_price(&mut self, symbol: Pubkey) -> Result<(), ProgramError> { | ||
let symbol_index = self | ||
.symbols | ||
.iter() | ||
.position(|&x| x == symbol) | ||
.unwrap_or(self.num_symbols); | ||
|
||
if symbol_index == self.num_symbols { | ||
if self.num_symbols == PC_MAX_SYMBOLS as usize { | ||
return Err(ProgramError::AccountDataTooSmall); | ||
} | ||
|
||
self.symbols[self.num_symbols] = symbol; | ||
self.num_symbols += 1; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn del_price(&mut self, symbol: Pubkey) -> Result<(), ProgramError> { | ||
let symbol_index = self | ||
.symbols | ||
.iter() | ||
.position(|&x| x == symbol) | ||
.ok_or(ProgramError::InvalidArgument)?; | ||
|
||
// update symbol list | ||
self.symbols[symbol_index] = self.symbols[self.num_symbols - 1]; | ||
self.symbols[self.num_symbols - 1] = Pubkey::default(); | ||
|
||
// update publisher permissions | ||
for i in 0..self.num_publishers { | ||
let value = self.get_publisher_permission(i, self.num_symbols - 1); | ||
self.set_publisher_permission(i, symbol_index, value) | ||
} | ||
|
||
self.num_symbols -= 1; | ||
self.calculate_scores() | ||
} | ||
|
||
pub fn calculate_scores(&mut self) -> Result<(), ProgramError> { | ||
let symbol_scores: Vec<u32> = self | ||
.symbols | ||
.iter() | ||
.enumerate() | ||
.map(|(j, _)| { | ||
let score = self | ||
.publisher_permissions | ||
.iter() | ||
.fold(0, |score, permissions| score + permissions[j] as u32); | ||
keyvankhademi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
max(score, self.z) | ||
}) | ||
.collect(); | ||
|
||
for i in 0..self.num_publishers { | ||
self.scores[i] = self | ||
.symbols | ||
.iter() | ||
.enumerate() | ||
.filter(|(j, _)| self.get_publisher_permission(i, *j)) | ||
.map(|(j, _)| 1f64 / symbol_scores[j] as f64) | ||
.sum(); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl PythAccount for PublisherScoresAccount { | ||
const ACCOUNT_TYPE: u32 = PC_ACCTYPE_SCORE; | ||
// Calculate the initial size of the account | ||
const INITIAL_SIZE: u32 = 1000; | ||
keyvankhademi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Unsafe impl because product_list is of size 640 and there's no derived trait for this size | ||
unsafe impl Pod for PublisherScoresAccount { | ||
keyvankhademi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
unsafe impl Zeroable for PublisherScoresAccount { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what we do if we exceed this numbers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a Pythnet v2 problem anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The program doesn't allow exceeding these numbers, we will probably face a lot of issues if we decide to increase these numbers. We are hoping to go to pythnet V2 before we need to increase these numbers. From the trasactions limit that we currently have, i don't think this will an issue.
But if you think there is a chance that we exceed these number before pythnet v2, we better address it now.