Skip to content

Commit c9aa1e3

Browse files
committed
test: test aggregation toggle
1 parent 847b3f5 commit c9aa1e3

File tree

1 file changed

+132
-55
lines changed

1 file changed

+132
-55
lines changed

program/rust/src/tests/test_aggregate_v2.rs

Lines changed: 132 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,96 +6,173 @@ use {
66
PriceAccountFlags,
77
PythAccount,
88
},
9-
c_oracle_header::PC_VERSION,
10-
deserialize::load_checked,
9+
c_oracle_header::{
10+
PC_STATUS_TRADING,
11+
PC_VERSION,
12+
},
13+
deserialize::{
14+
load_checked,
15+
load_mut,
16+
},
1117
instruction::{
1218
AddPublisherArgs,
1319
OracleCommand,
20+
UpdPriceArgs,
1421
},
1522
processor::{
1623
process_instruction,
24+
DISABLE_ACCUMULATOR_V2,
1725
ENABLE_ACCUMULATOR_V2,
1826
},
19-
tests::test_utils::AccountSetup,
27+
tests::test_utils::{
28+
update_clock_slot,
29+
AccountSetup,
30+
},
2031
},
2132
bytemuck::bytes_of,
2233
solana_program::{
2334
pubkey::Pubkey,
2435
rent::Rent,
2536
},
37+
solana_sdk::account_info::AccountInfo,
38+
std::mem::size_of,
2639
};
2740

28-
#[test]
29-
fn test_aggregate_v2() {
30-
let program_id = Pubkey::new_unique();
31-
let publisher = Pubkey::new_unique();
32-
33-
let mut cmd = AddPublisherArgs {
34-
header: OracleCommand::AddPublisher.into(),
35-
publisher,
36-
};
37-
let mut instruction_data = bytes_of::<AddPublisherArgs>(&cmd);
38-
39-
let mut funding_setup = AccountSetup::new_funding();
40-
let funding_account = funding_setup.as_account_info();
41+
struct Accounts {
42+
program_id: Pubkey,
43+
publisher_account: AccountSetup,
44+
funding_account: AccountSetup,
45+
price_account: AccountSetup,
46+
permissions_account: AccountSetup,
47+
clock_account: AccountSetup,
48+
}
4149

42-
let mut price_setup = AccountSetup::new::<PriceAccount>(&program_id);
43-
let price_account = price_setup.as_account_info();
44-
PriceAccount::initialize(&price_account, PC_VERSION).unwrap();
50+
impl Accounts {
51+
fn new() -> Self {
52+
let program_id = Pubkey::new_unique();
53+
let publisher_account = AccountSetup::new_funding();
54+
let clock_account = AccountSetup::new_clock();
55+
let mut funding_account = AccountSetup::new_funding();
56+
let mut permissions_account = AccountSetup::new_permission(&program_id);
57+
let mut price_account = AccountSetup::new::<PriceAccount>(&program_id);
4558

46-
**price_account.try_borrow_mut_lamports().unwrap() = 100;
59+
PriceAccount::initialize(&price_account.as_account_info(), PC_VERSION).unwrap();
4760

48-
let mut permissions_setup = AccountSetup::new_permission(&program_id);
49-
let permissions_account = permissions_setup.as_account_info();
61+
{
62+
let permissions_account_info = permissions_account.as_account_info();
63+
let mut permissions_account_data =
64+
PermissionAccount::initialize(&permissions_account_info, PC_VERSION).unwrap();
65+
permissions_account_data.master_authority = *funding_account.as_account_info().key;
66+
permissions_account_data.data_curation_authority =
67+
*funding_account.as_account_info().key;
68+
permissions_account_data.security_authority = *funding_account.as_account_info().key;
69+
}
5070

51-
{
52-
let mut permissions_account_data =
53-
PermissionAccount::initialize(&permissions_account, PC_VERSION).unwrap();
54-
permissions_account_data.master_authority = *funding_account.key;
55-
permissions_account_data.data_curation_authority = *funding_account.key;
56-
permissions_account_data.security_authority = *funding_account.key;
71+
Self {
72+
program_id,
73+
publisher_account,
74+
funding_account,
75+
price_account,
76+
permissions_account,
77+
clock_account,
78+
}
5779
}
80+
}
5881

59-
// Give the price account enough lamports to be rent exempt
60-
**price_account.try_borrow_mut_lamports().unwrap() =
61-
Rent::minimum_balance(&Rent::default(), PriceAccount::MINIMUM_SIZE);
82+
fn add_publisher(accounts: &mut Accounts, publisher: Option<Pubkey>) {
83+
let args = AddPublisherArgs {
84+
header: OracleCommand::AddPublisher.into(),
85+
publisher: publisher.unwrap_or(*accounts.publisher_account.as_account_info().key),
86+
};
6287

6388
assert!(process_instruction(
64-
&program_id,
89+
&accounts.program_id,
6590
&[
66-
funding_account.clone(),
67-
price_account.clone(),
68-
permissions_account.clone(),
91+
accounts.funding_account.as_account_info(),
92+
accounts.price_account.as_account_info(),
93+
accounts.permissions_account.as_account_info(),
6994
],
70-
instruction_data
95+
bytes_of::<AddPublisherArgs>(&args)
7196
)
7297
.is_ok());
98+
}
7399

74-
{
75-
let price_data = load_checked::<PriceAccount>(&price_account, PC_VERSION).unwrap();
76-
assert_eq!(price_data.num_, 1);
77-
assert_eq!(price_data.header.size, PriceAccount::INITIAL_SIZE);
78-
assert!(price_data.comp_[0].pub_ == publisher);
79-
// Make sure that v2 aggregation is disabled
80-
assert!(!price_data.flags.contains(PriceAccountFlags::ACCUMULATOR_V2));
81-
}
100+
fn update_price(accounts: &mut Accounts, price: i64, conf: u64, slot: u64) {
101+
let instruction_data = &mut [0u8; size_of::<UpdPriceArgs>()];
102+
let mut cmd = load_mut::<UpdPriceArgs>(instruction_data).unwrap();
103+
cmd.header = OracleCommand::UpdPrice.into();
104+
cmd.status = PC_STATUS_TRADING;
105+
cmd.price = price;
106+
cmd.confidence = conf;
107+
cmd.publishing_slot = slot;
108+
cmd.unused_ = 0;
82109

83-
cmd.publisher = ENABLE_ACCUMULATOR_V2.into();
84-
instruction_data = bytes_of::<AddPublisherArgs>(&cmd);
85-
assert!(process_instruction(
86-
&program_id,
110+
let mut clock = accounts.clock_account.as_account_info();
111+
clock.is_signer = false;
112+
clock.is_writable = false;
113+
114+
process_instruction(
115+
&accounts.program_id,
87116
&[
88-
funding_account.clone(),
89-
price_account.clone(),
90-
permissions_account.clone(),
117+
accounts.publisher_account.as_account_info(),
118+
accounts.price_account.as_account_info(),
119+
clock,
91120
],
92-
instruction_data
121+
instruction_data,
93122
)
94-
.is_ok());
123+
.unwrap();
124+
}
125+
126+
#[test]
127+
fn test_aggregate_v2_toggle() {
128+
let accounts = &mut Accounts::new();
129+
130+
// Add an initial Publisher to test with.
131+
add_publisher(accounts, None);
132+
133+
// Update the price, no aggregation will happen on the first slot.
134+
{
135+
update_clock_slot(&mut accounts.clock_account.as_account_info(), 1);
136+
update_price(accounts, 42, 2, 1);
137+
let info = accounts.price_account.as_account_info();
138+
let price_data = load_checked::<PriceAccount>(&info, PC_VERSION).unwrap();
139+
assert_eq!(price_data.last_slot_, 0);
140+
assert!(!price_data.flags.contains(PriceAccountFlags::ACCUMULATOR_V2));
141+
}
142+
143+
// Update again, component is now TRADING so aggregation should trigger.
144+
{
145+
update_clock_slot(&mut accounts.clock_account.as_account_info(), 2);
146+
update_price(accounts, 42, 2, 2);
147+
let info = accounts.price_account.as_account_info();
148+
let price_data = load_checked::<PriceAccount>(&info, PC_VERSION).unwrap();
149+
assert_eq!(price_data.last_slot_, 2);
150+
assert!(!price_data.flags.contains(PriceAccountFlags::ACCUMULATOR_V2));
151+
}
95152

96-
// Make sure that v2 aggregation is enabled
153+
// Enable v2 Aggregation
154+
add_publisher(accounts, Some(ENABLE_ACCUMULATOR_V2.into()));
155+
156+
// Update again, with accumulator bit set, aggregation should not have
157+
// happened, as its now the validators job.
97158
{
98-
let price_data = load_checked::<PriceAccount>(&price_account, PC_VERSION).unwrap();
159+
update_clock_slot(&mut accounts.clock_account.as_account_info(), 3);
160+
update_price(accounts, 42, 2, 3);
161+
let info = accounts.price_account.as_account_info();
162+
let price_data = load_checked::<PriceAccount>(&info, PC_VERSION).unwrap();
163+
assert_eq!(price_data.last_slot_, 2);
99164
assert!(price_data.flags.contains(PriceAccountFlags::ACCUMULATOR_V2));
100165
}
166+
167+
add_publisher(accounts, Some(DISABLE_ACCUMULATOR_V2.into()));
168+
169+
// Confirm disabling v2 Aggregation re-enables the aggregation flow.
170+
{
171+
update_clock_slot(&mut accounts.clock_account.as_account_info(), 4);
172+
update_price(accounts, 42, 2, 4);
173+
let info = accounts.price_account.as_account_info();
174+
let price_data = load_checked::<PriceAccount>(&info, PC_VERSION).unwrap();
175+
assert_eq!(price_data.last_slot_, 4);
176+
assert!(!price_data.flags.contains(PriceAccountFlags::ACCUMULATOR_V2));
177+
}
101178
}

0 commit comments

Comments
 (0)