@@ -1280,6 +1280,23 @@ pub struct CommitTransactionCounts {
1280
1280
pub signature_count: u64,
1281
1281
}
1282
1282
1283
+ /// Accumulator specific error type. It would be nice to use `transaction::Error` but it does
1284
+ /// not include any `Custom` style variant we can leverage, so we introduce our own.
1285
+ #[derive(Debug, thiserror::Error)]
1286
+ enum AccumulatorUpdateError {
1287
+ #[error("get_program_accounts failed to return accounts")]
1288
+ GetProgramAccounts,
1289
+
1290
+ #[error("failed to serialize sequence account")]
1291
+ FailedSequenceSerialization,
1292
+
1293
+ #[error("failed to serialize message account")]
1294
+ FailedMessageSerialization,
1295
+
1296
+ #[error("io error")]
1297
+ Io(#[from] std::io::Error),
1298
+ }
1299
+
1283
1300
impl Bank {
1284
1301
pub fn default_for_tests() -> Self {
1285
1302
Self::default_with_accounts(Accounts::default_for_tests())
@@ -2480,12 +2497,15 @@ impl Bank {
2480
2497
///
2481
2498
/// Note:
2482
2499
/// - Library imports are placed within this function to keep the diff against upstream small.
2483
- /// - Functionality is kept in the `solana-pyth` library to contain our new dependencies.
2484
2500
/// - This update will incur a performance hit on each slot, so must be kept efficient.
2485
- /// - Focused on Merkle temporarily and will be generalized to the Accumulator trait.
2486
- ///
2487
- /// TODO: Remove dangerous unwrap() calls.
2501
+ /// - Focused on Merkle for initial release but will generalise to more accumulators in future.
2488
2502
fn update_accumulator(&self) {
2503
+ if let Err(e) = self.update_accumulator_impl() {
2504
+ error!("Error updating accumulator: {:?}", e);
2505
+ }
2506
+ }
2507
+
2508
+ fn update_accumulator_impl(&self) -> std::result::Result<(), AccumulatorUpdateError> {
2489
2509
use {
2490
2510
byteorder::ReadBytesExt,
2491
2511
solana_pyth::{
@@ -2506,9 +2526,8 @@ impl Bank {
2506
2526
let accumulator_program =
2507
2527
Pubkey::from_str("Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM").unwrap();
2508
2528
2509
- let accounts = self
2510
- .get_program_accounts(&accumulator_program, &ScanConfig::new(true))
2511
- .unwrap();
2529
+ let accounts = self.get_program_accounts(&accumulator_program, &ScanConfig::new(true))
2530
+ .map_err(|_| AccumulatorUpdateError::GetProgramAccounts)?;
2512
2531
2513
2532
// Filter accounts that don't match the Anchor sighash.
2514
2533
let accounts = accounts.iter().filter(|(_, account)| {
@@ -2524,13 +2543,13 @@ impl Bank {
2524
2543
// This code, using the offsets in each Account, extracts the various data versions from
2525
2544
// the account. We deduplicate this result because the accumulator expects a set.
2526
2545
let accounts = accounts
2527
- .flat_map (|(_, account)| {
2546
+ .map (|(_, account)| {
2528
2547
let data = account.data();
2529
2548
let mut cursor = std::io::Cursor::new(&data);
2530
- let _sighash = cursor.read_u64::<LittleEndian>().unwrap() ;
2531
- let _bump = cursor.read_u8().unwrap() ;
2532
- let _version = cursor.read_u8().unwrap() ;
2533
- let header_len = cursor.read_u16::<LittleEndian>().unwrap() ;
2549
+ let _sighash = cursor.read_u64::<LittleEndian>()? ;
2550
+ let _bump = cursor.read_u8()? ;
2551
+ let _version = cursor.read_u8()? ;
2552
+ let header_len = cursor.read_u16::<LittleEndian>()? ;
2534
2553
let mut header_begin = header_len;
2535
2554
let mut inputs = Vec::new();
2536
2555
while let Some(end) = cursor.read_u16::<LittleEndian>().ok() {
@@ -2544,8 +2563,11 @@ impl Bank {
2544
2563
header_begin = end_offset;
2545
2564
}
2546
2565
2547
- inputs
2566
+ Ok( inputs)
2548
2567
})
2568
+ .collect::<std::result::Result<Vec<_>, std::io::Error>>()?
2569
+ .into_iter()
2570
+ .flatten()
2549
2571
.sorted_unstable()
2550
2572
.dedup();
2551
2573
@@ -2558,33 +2580,33 @@ impl Bank {
2558
2580
);
2559
2581
2560
2582
let accumulator_data = {
2561
- let data = accounts.clone().collect::<Vec<_>>();
2562
- let data = data.try_to_vec().unwrap();
2583
+ let data = accounts.clone().collect::<Vec<_>>().try_to_vec()?;
2563
2584
let owner = solana_sdk::system_program::id();
2564
2585
let balance = self.get_minimum_balance_for_rent_exemption(data.len());
2565
2586
let mut account = AccountSharedData::new(balance, data.len(), &owner);
2566
2587
account.set_data(data);
2567
2588
account
2568
2589
};
2569
2590
2570
- // Write the Account Set into `accumulator_state` so that the hermes application can
2571
- // request historical data to prove.
2572
- self.store_account_and_update_capitalization(&accumulator_account, &accumulator_data);
2573
-
2574
2591
// Generate a Message owned by Wormhole to be sent cross-chain. This short-circuits the
2575
2592
// Wormhole message generation code that would normally be called, but the Guardian
2576
2593
// set filters our messages so this does not pose a security risk.
2577
2594
if let Some(accumulator) = MerkleAccumulator::from_set(accounts) {
2578
- self.post_accumulator_attestation(accumulator);
2595
+ self.post_accumulator_attestation(accumulator)? ;
2579
2596
}
2597
+
2598
+ // Write the Account Set into `accumulator_state` so that the hermes application can
2599
+ // request historical data to prove.
2600
+ self.store_account_and_update_capitalization(&accumulator_account, &accumulator_data);
2601
+
2602
+ Ok(())
2580
2603
}
2581
2604
2582
- /// TODO: Remove dangerous unwrap() calls.
2583
2605
/// TODO: Safe integer conversion checks if any are missed.
2584
2606
fn post_accumulator_attestation(
2585
2607
&self,
2586
2608
acc: solana_pyth::accumulators::merkle::MerkleAccumulator,
2587
- ) {
2609
+ ) -> std::result::Result<(), AccumulatorUpdateError> {
2588
2610
use {
2589
2611
solana_pyth::{
2590
2612
wormhole::{AccumulatorSequenceTracker, MessageData, PostedMessageUnreliableData},
@@ -2625,9 +2647,11 @@ impl Bank {
2625
2647
},
2626
2648
};
2627
2649
2650
+ info!("msg_data.message: {:?}", message.message);
2651
+
2628
2652
// Now we can bump and write the Sequence account.
2629
2653
sequence.sequence += 1;
2630
- let sequence = sequence.try_to_vec().unwrap() ;
2654
+ let sequence = sequence.try_to_vec().map_err(|_| AccumulatorUpdateError::FailedSequenceSerialization)? ;
2631
2655
let sequence_balance = self.get_minimum_balance_for_rent_exemption(sequence.len());
2632
2656
let sequence_account = {
2633
2657
let owner = &WORMHOLE_PID;
@@ -2640,15 +2664,8 @@ impl Bank {
2640
2664
account
2641
2665
};
2642
2666
2643
- self.store_account_and_update_capitalization(
2644
- &Pubkey::new_from_array(ACCUMULATOR_SEQUENCE_ADDR),
2645
- &sequence_account,
2646
- );
2647
-
2648
- info!("msg_data.message: {:?}", message.message);
2649
-
2650
2667
// Serialize into (and create if necesary) the message account.
2651
- let message = message.try_to_vec().unwrap() ;
2668
+ let message = message.try_to_vec().map_err(|_| AccumulatorUpdateError::FailedMessageSerialization)? ;
2652
2669
let message_balance = self.get_minimum_balance_for_rent_exemption(message.len());
2653
2670
let message_account = {
2654
2671
let owner = &WORMHOLE_PID;
@@ -2667,7 +2684,14 @@ impl Bank {
2667
2684
&Pubkey::new_from_array(WORMHOLE_PID),
2668
2685
);
2669
2686
2687
+ self.store_account_and_update_capitalization(
2688
+ &Pubkey::new_from_array(ACCUMULATOR_SEQUENCE_ADDR),
2689
+ &sequence_account,
2690
+ );
2691
+
2670
2692
self.store_account_and_update_capitalization(&message_pda, &message_account);
2693
+
2694
+ Ok(())
2671
2695
}
2672
2696
2673
2697
pub fn epoch_duration_in_years(&self, prev_epoch: Epoch) -> f64 {
0 commit comments