Skip to content

Commit 4502c6d

Browse files
authored
[accumulator-updater 3/x] Update Inputs Ix (#741)
* feat(accumulator_updater): initial skeleton for accumulator_udpater program Initial layout for accumulator updater program. Includes mock-cpi-caller which is meant to represent pyth oracle(or any future allowed program) that will call the accumulator updater program. All implementation details are open for discussion/subject to change * test(accumulator_updater): add additional checks in tests and minor clean up * chore(accumulator_updater): misc clean-up * refactor(accumulator_updater): added comments & to-dos and minor refactoring to address PR comments * feat(accumulator_updater): nmanual serialization for mock-cpi-caller schemas & use zero-copy * chore(accumulator-updater): misc clean-up * refactor(accumulator-updater): rename parameter in accumulator-updater::initalize ix for consistency * style(accumulator-updater): switch PriceAccountType enum variants to camelcase * refactor(accumulator-updater): address PR comments rename schema to message & associated price messages, remove unncessary comments, changed addAllowedProgram to setAllowedPrograms * refactor(accumulator-updater): address more PR comments consolidate SetAllowedPrograms and UpdateWhitelistAuthority into one context * style(accumulator-updater): minor style fixes to address PR comments * feat(accumulator-updater): implement update-inputs ix, add bump to AccumulatorInput header * feat(accumulator-updater): implement update ix * refactor(accumulator-updater): refactor ixs & state into modules * docs(accumulator-updater): add comments for ixs * feat(accumulator-updater): consolidate add/update_inputs into emit_inputs ix (#743) * refactor(accumulator-updater): clean up unused fn, rename fns * fix(accumulator-updater): fix error from resolving merge conflicts * refactor(accumulator_updater): address PR comments Remove account_type, rename emit_inputs to put_all to be more similar to a Map interface, added AccumulatorHeader::CURRENT_VERSION * docs(accumulator_updater): add docs for AccumulatorInput struct
1 parent c3b2322 commit 4502c6d

File tree

16 files changed

+867
-512
lines changed

16 files changed

+867
-512
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub use put_all::*;
2+
3+
mod put_all;
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use {
2+
crate::{
3+
state::*,
4+
AccumulatorUpdaterError,
5+
},
6+
anchor_lang::{
7+
prelude::*,
8+
system_program::{
9+
self,
10+
CreateAccount,
11+
},
12+
},
13+
};
14+
15+
#[derive(AnchorSerialize, AnchorDeserialize)]
16+
pub struct InputSchemaAndData {
17+
pub schema: u8,
18+
pub data: Vec<u8>,
19+
}
20+
21+
22+
pub fn put_all<'info>(
23+
ctx: Context<'_, '_, '_, 'info, PutAll<'info>>,
24+
base_account_key: Pubkey,
25+
values: Vec<InputSchemaAndData>,
26+
) -> Result<()> {
27+
let cpi_caller = ctx.accounts.whitelist_verifier.is_allowed()?;
28+
let account_infos = ctx.remaining_accounts;
29+
require_eq!(account_infos.len(), values.len());
30+
31+
let rent = Rent::get()?;
32+
let (mut initialized, mut updated) = (vec![], vec![]);
33+
34+
for (
35+
ai,
36+
InputSchemaAndData {
37+
schema: account_schema,
38+
data: account_data,
39+
},
40+
) in account_infos.iter().zip(values)
41+
{
42+
let bump = if is_uninitialized_account(ai) {
43+
let seeds = &[
44+
cpi_caller.as_ref(),
45+
b"accumulator".as_ref(),
46+
base_account_key.as_ref(),
47+
&account_schema.to_le_bytes(),
48+
];
49+
let (pda, bump) = Pubkey::find_program_address(seeds, &crate::ID);
50+
require_keys_eq!(ai.key(), pda);
51+
52+
53+
//TODO: Update this with serialization logic
54+
// 8 for anchor discriminator
55+
let accumulator_size = 8 + AccumulatorInput::size(&account_data);
56+
PutAll::create_account(
57+
ai,
58+
accumulator_size,
59+
&ctx.accounts.payer,
60+
&[
61+
cpi_caller.as_ref(),
62+
b"accumulator".as_ref(),
63+
base_account_key.as_ref(),
64+
&account_schema.to_le_bytes(),
65+
&[bump],
66+
],
67+
&rent,
68+
&ctx.accounts.system_program,
69+
)?;
70+
initialized.push(ai.key());
71+
72+
bump
73+
} else {
74+
let accumulator_input = <AccumulatorInput as AccountDeserialize>::try_deserialize(
75+
&mut &**ai.try_borrow_mut_data()?,
76+
)?;
77+
{
78+
// TODO: allow re-sizing?
79+
require_gte!(
80+
accumulator_input.data.len(),
81+
account_data.len(),
82+
AccumulatorUpdaterError::CurrentDataLengthExceeded
83+
);
84+
85+
accumulator_input.validate(
86+
ai.key(),
87+
cpi_caller,
88+
base_account_key,
89+
account_schema,
90+
)?;
91+
}
92+
93+
94+
updated.push(ai.key());
95+
accumulator_input.header.bump
96+
};
97+
98+
let accumulator_input =
99+
AccumulatorInput::new(AccumulatorHeader::new(bump, account_schema), account_data);
100+
accumulator_input.persist(ai)?;
101+
}
102+
103+
msg!(
104+
"[emit-updates]: initialized: {:?}, updated: {:?}",
105+
initialized,
106+
updated
107+
);
108+
Ok(())
109+
}
110+
111+
pub fn is_uninitialized_account(ai: &AccountInfo) -> bool {
112+
ai.data_is_empty() && ai.owner == &system_program::ID
113+
}
114+
115+
#[derive(Accounts)]
116+
pub struct PutAll<'info> {
117+
#[account(mut)]
118+
pub payer: Signer<'info>,
119+
pub whitelist_verifier: WhitelistVerifier<'info>,
120+
pub system_program: Program<'info, System>,
121+
// remaining_accounts: - [AccumulatorInput PDAs]
122+
}
123+
124+
impl<'info> PutAll<'info> {
125+
fn create_account<'a>(
126+
account_info: &AccountInfo<'a>,
127+
space: usize,
128+
payer: &AccountInfo<'a>,
129+
seeds: &[&[u8]],
130+
rent: &Rent,
131+
system_program: &AccountInfo<'a>,
132+
) -> Result<()> {
133+
let lamports = rent.minimum_balance(space);
134+
135+
system_program::create_account(
136+
CpiContext::new_with_signer(
137+
system_program.to_account_info(),
138+
CreateAccount {
139+
from: payer.to_account_info(),
140+
to: account_info.to_account_info(),
141+
},
142+
&[seeds],
143+
),
144+
lamports,
145+
space.try_into().unwrap(),
146+
&crate::ID,
147+
)?;
148+
Ok(())
149+
}
150+
}

0 commit comments

Comments
 (0)