|
7 | 7 | },
|
8 | 8 | bank::{
|
9 | 9 | pyth_accumulator::{
|
10 |
| - get_accumulator_keys, ACCUMULATOR_RING_SIZE, ORACLE_PID, STAKE_CAPS_PARAMETERS_ADDR, |
| 10 | + get_accumulator_keys, ACCUMULATOR_RING_SIZE, BATCH_PUBLISH_PID, ORACLE_PID, |
| 11 | + STAKE_CAPS_PARAMETERS_ADDR, |
11 | 12 | },
|
| 13 | + pyth_batch_publish::publisher_prices_account::{self, PublisherPrice}, |
12 | 14 | Bank,
|
13 | 15 | },
|
14 | 16 | genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo},
|
15 | 17 | },
|
| 18 | + bytemuck::{cast_slice, checked::from_bytes}, |
16 | 19 | byteorder::{ByteOrder, LittleEndian, ReadBytesExt},
|
17 | 20 | itertools::Itertools,
|
18 | 21 | pyth_oracle::{
|
@@ -48,7 +51,9 @@ fn create_new_bank_for_tests_with_index(genesis_config: &GenesisConfig) -> Bank
|
48 | 51 | AccountSecondaryIndexes {
|
49 | 52 | keys: Some(AccountSecondaryIndexesIncludeExclude {
|
50 | 53 | exclude: false,
|
51 |
| - keys: [*ORACLE_PID, *MESSAGE_BUFFER_PID].into_iter().collect(), |
| 54 | + keys: [*ORACLE_PID, *MESSAGE_BUFFER_PID, *BATCH_PUBLISH_PID] |
| 55 | + .into_iter() |
| 56 | + .collect(), |
52 | 57 | }),
|
53 | 58 | indexes: [AccountIndex::ProgramId].into_iter().collect(),
|
54 | 59 | },
|
@@ -1005,8 +1010,6 @@ fn test_publisher_stake_caps() {
|
1005 | 1010 | ],
|
1006 | 1011 | ),
|
1007 | 1012 | generate_price(&bank, b"seeds_5", false, &[]),
|
1008 |
| - |
1009 |
| - |
1010 | 1013 | ];
|
1011 | 1014 |
|
1012 | 1015 | // Publishers are sorted in the publisher stake caps message so we sort them here too
|
@@ -1072,9 +1075,7 @@ fn test_publisher_stake_caps() {
|
1072 | 1075 | // We add some badly formatted stake cap parameters
|
1073 | 1076 | let mut stake_cap_parameters_account =
|
1074 | 1077 | AccountSharedData::new(42, size_of::<StakeCapParameters>(), &ORACLE_PID);
|
1075 |
| - stake_cap_parameters_account.set_data( |
1076 |
| - vec![1,2,3,4], |
1077 |
| - ); |
| 1078 | + stake_cap_parameters_account.set_data(vec![1, 2, 3, 4]); |
1078 | 1079 | bank.store_account(&STAKE_CAPS_PARAMETERS_ADDR, &stake_cap_parameters_account);
|
1079 | 1080 |
|
1080 | 1081 | // Nothing should change as the stake cap parameters are invalid
|
@@ -1144,3 +1145,128 @@ fn test_get_accumulator_keys() {
|
1144 | 1145 | ];
|
1145 | 1146 | assert_eq!(accumulator_keys, expected_pyth_keys);
|
1146 | 1147 | }
|
| 1148 | + |
| 1149 | +#[test] |
| 1150 | +fn test_batch_publish() { |
| 1151 | + let leader_pubkey = solana_sdk::pubkey::new_rand(); |
| 1152 | + let GenesisConfigInfo { |
| 1153 | + mut genesis_config, .. |
| 1154 | + } = create_genesis_config_with_leader(5, &leader_pubkey, 3); |
| 1155 | + |
| 1156 | + // Set epoch length to 32 so we can advance epochs quickly. We also skip past slot 0 here |
| 1157 | + // due to slot 0 having special handling. |
| 1158 | + let slots_in_epoch = 32; |
| 1159 | + genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch); |
| 1160 | + let mut bank = create_new_bank_for_tests_with_index(&genesis_config); |
| 1161 | + |
| 1162 | + let generate_publisher = |seed, new_prices| { |
| 1163 | + let publisher1_key = keypair_from_seed(seed).unwrap(); |
| 1164 | + |
| 1165 | + let (publisher1_prices_key, _bump) = Pubkey::find_program_address( |
| 1166 | + // TODO: real seed |
| 1167 | + &[ |
| 1168 | + b"PUBLISHER_PRICES_ACCOUNT", |
| 1169 | + &publisher1_key.pubkey().to_bytes(), |
| 1170 | + ], |
| 1171 | + &BATCH_PUBLISH_PID, |
| 1172 | + ); |
| 1173 | + let mut publisher1_prices_account = |
| 1174 | + AccountSharedData::new(42, publisher_prices_account::size(100), &BATCH_PUBLISH_PID); |
| 1175 | + { |
| 1176 | + let (header, prices) = publisher_prices_account::create( |
| 1177 | + publisher1_prices_account.data_mut(), |
| 1178 | + publisher1_key.pubkey().to_bytes(), |
| 1179 | + ) |
| 1180 | + .unwrap(); |
| 1181 | + publisher_prices_account::extend(header, prices, cast_slice(new_prices)).unwrap(); |
| 1182 | + } |
| 1183 | + bank.store_account(&publisher1_prices_key, &publisher1_prices_account); |
| 1184 | + |
| 1185 | + publisher1_key |
| 1186 | + }; |
| 1187 | + |
| 1188 | + let publishers = [ |
| 1189 | + generate_publisher( |
| 1190 | + &[1u8; 32], |
| 1191 | + &[ |
| 1192 | + PublisherPrice::new(1, 1, 10, 2).unwrap(), |
| 1193 | + PublisherPrice::new(2, 1, 20, 3).unwrap(), |
| 1194 | + ], |
| 1195 | + ), |
| 1196 | + generate_publisher( |
| 1197 | + &[2u8; 32], |
| 1198 | + &[ |
| 1199 | + PublisherPrice::new(1, 1, 15, 2).unwrap(), |
| 1200 | + PublisherPrice::new(2, 1, 25, 3).unwrap(), |
| 1201 | + ], |
| 1202 | + ), |
| 1203 | + ]; |
| 1204 | + |
| 1205 | + let generate_price = |seeds, index| { |
| 1206 | + let (price_feed_key, _bump) = Pubkey::find_program_address(&[seeds], &ORACLE_PID); |
| 1207 | + let mut price_feed_account = |
| 1208 | + AccountSharedData::new(42, size_of::<PriceAccount>(), &ORACLE_PID); |
| 1209 | + |
| 1210 | + let messages = { |
| 1211 | + let price_feed_info_key = &price_feed_key.to_bytes().into(); |
| 1212 | + let price_feed_info_lamports = &mut 0; |
| 1213 | + let price_feed_info_owner = &ORACLE_PID.to_bytes().into(); |
| 1214 | + let price_feed_info_data = price_feed_account.data_mut(); |
| 1215 | + let price_feed_info = AccountInfo::new( |
| 1216 | + price_feed_info_key, |
| 1217 | + false, |
| 1218 | + true, |
| 1219 | + price_feed_info_lamports, |
| 1220 | + price_feed_info_data, |
| 1221 | + price_feed_info_owner, |
| 1222 | + false, |
| 1223 | + Epoch::default(), |
| 1224 | + ); |
| 1225 | + |
| 1226 | + let mut price_account = PriceAccount::initialize(&price_feed_info, 0).unwrap(); |
| 1227 | + price_account.flags.insert( |
| 1228 | + PriceAccountFlags::ACCUMULATOR_V2 | PriceAccountFlags::MESSAGE_BUFFER_CLEARED, |
| 1229 | + ); |
| 1230 | + price_account.unused_3_ = index; |
| 1231 | + price_account.comp_[0].pub_ = publishers[0].pubkey().to_bytes().into(); |
| 1232 | + price_account.comp_[1].pub_ = publishers[1].pubkey().to_bytes().into(); |
| 1233 | + price_account.num_ = 2; |
| 1234 | + }; |
| 1235 | + |
| 1236 | + bank.store_account(&price_feed_key, &price_feed_account); |
| 1237 | + (price_feed_key, messages) |
| 1238 | + }; |
| 1239 | + |
| 1240 | + assert!(bank |
| 1241 | + .feature_set |
| 1242 | + .is_active(&feature_set::enable_accumulator_sysvar::id())); |
| 1243 | + assert!(bank |
| 1244 | + .feature_set |
| 1245 | + .is_active(&feature_set::move_accumulator_to_end_of_block::id())); |
| 1246 | + assert!(bank |
| 1247 | + .feature_set |
| 1248 | + .is_active(&feature_set::undo_move_accumulator_to_end_of_block::id())); |
| 1249 | + assert!(bank |
| 1250 | + .feature_set |
| 1251 | + .is_active(&feature_set::redo_move_accumulator_to_end_of_block::id())); |
| 1252 | + |
| 1253 | + let prices_with_messages = [ |
| 1254 | + generate_price(b"seeds_1", 1), |
| 1255 | + generate_price(b"seeds_2", 2), |
| 1256 | + generate_price(b"seeds_3", 3), |
| 1257 | + generate_price(b"seeds_4", 4), |
| 1258 | + ]; |
| 1259 | + |
| 1260 | + bank = new_from_parent(&Arc::new(bank)); // Advance slot 1. |
| 1261 | + bank = new_from_parent(&Arc::new(bank)); // Advance slot 2. |
| 1262 | + |
| 1263 | + let new_price_feed1_account = bank.get_account(&prices_with_messages[0].0).unwrap(); |
| 1264 | + let new_price_feed1_data: &PriceAccount = from_bytes(new_price_feed1_account.data()); |
| 1265 | + assert_eq!(new_price_feed1_data.comp_[0].latest_.price_, 10); |
| 1266 | + assert_eq!(new_price_feed1_data.comp_[1].latest_.price_, 15); |
| 1267 | + |
| 1268 | + let new_price_feed2_account = bank.get_account(&prices_with_messages[1].0).unwrap(); |
| 1269 | + let new_price_feed2_data: &PriceAccount = from_bytes(new_price_feed2_account.data()); |
| 1270 | + assert_eq!(new_price_feed2_data.comp_[0].latest_.price_, 20); |
| 1271 | + assert_eq!(new_price_feed2_data.comp_[1].latest_.price_, 25); |
| 1272 | +} |
0 commit comments