-
Notifications
You must be signed in to change notification settings - Fork 102
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
feat(oracle): WIP add scores account #407
base: main
Are you sure you want to change the base?
Changes from 5 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,188 @@ | ||
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)] | ||
/* | ||
* This account is part of Community Integrity Pool (CIP) project. | ||
* It is used to store the caps of the publishers which will be sent | ||
* to the `integrity_pool` program on mainnet to calculate the rewards. | ||
*/ | ||
keyvankhademi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pub struct PublisherCapsAccount { | ||
pub header: AccountHeader, | ||
pub num_publishers: usize, | ||
pub num_symbols: usize, | ||
// Z is a constant used to normalize the scores | ||
pub z: u32, | ||
// M is a constant showing the target stake per symbol | ||
pub m: 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 caps: [f64; PC_MAX_PUBLISHERS as usize], | ||
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 PublisherCapsAccount { | ||
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.caps[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 PublisherCapsAccount { | ||
const ACCOUNT_TYPE: u32 = PC_ACCTYPE_SCORE; | ||
// Calculate the initial size of the account | ||
const INITIAL_SIZE: u32 = 75816; | ||
} | ||
|
||
// Unsafe impl because product_list is of size 640 and there's no derived trait for this size | ||
unsafe impl Pod for PublisherCapsAccount { | ||
} | ||
|
||
unsafe impl Zeroable for PublisherCapsAccount { | ||
} |
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.