Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3237,21 +3237,39 @@ impl Bank {
// If accumulator move to end of block is active update the accumulator before doing
// other tasks when freezing to avoid any conflicts.
if accumulator_moved_to_end_of_block {
let mut measure = Measure::start("accumulator");
pyth_accumulator::update_accumulator(self);
measure.stop();

debug!(
"Accumulator: Updated accumulator before freezing. Slot: {}, time: {}us",
self.slot(),
measure.as_us(),
);
} else {
info!(
"Accumulator: Skipping accumulating end of block because the feature is disabled. Slot: {}",
self.slot()
);
}

let mut measure = Measure::start("freeze");

// finish up any deferred changes to account state
self.collect_rent_eagerly(false);
self.collect_fees();
self.distribute_rent();
self.update_slot_history();
self.run_incinerator();

measure.stop();
debug!(
"Bank frozen (non-accumulator): {} slot {} time: {}us",
self.collector_id,
self.slot(),
measure.as_us()
);

// freeze is a one-way trip, idempotent
self.freeze_started.store(true, Relaxed);
*hash = self.hash_internal_state();
Expand Down
92 changes: 86 additions & 6 deletions runtime/src/bank/pyth_accumulator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
super::Bank,
crate::accounts_index::{ScanConfig, ScanError},
crate::accounts_index::{IndexKey, ScanConfig, ScanError},
byteorder::{LittleEndian, ReadBytesExt},
log::*,
pyth_oracle::validator::AggregationError,
Expand All @@ -9,6 +9,7 @@ use {
hashers::keccak256_160::Keccak160,
wormhole::{AccumulatorSequenceTracker, MessageData, PostedMessageUnreliableData},
},
solana_measure::measure::Measure,
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
borsh, feature_set,
Expand Down Expand Up @@ -136,10 +137,29 @@ pub fn update_v1(

let message_buffer_accounts;
let v1_messages = if use_message_buffers {
let mut measure = Measure::start("update_v1_load_program_accounts");

assert!(
bank.account_indexes_include_key(&*MESSAGE_BUFFER_PID),
"MessageBuffer program account index missing"
);
message_buffer_accounts = bank
.get_program_accounts(&MESSAGE_BUFFER_PID, &ScanConfig::new(true))
.get_filtered_indexed_accounts(
&IndexKey::ProgramId(*MESSAGE_BUFFER_PID),
|account| account.owner() == &*MESSAGE_BUFFER_PID,
&ScanConfig::new(true),
None,
)
.map_err(AccumulatorUpdateErrorV1::GetProgramAccounts)?;

measure.stop();
debug!(
"Accumulator: Loaded message buffer accounts in {}us",
measure.as_us()
);

let mut measure = Measure::start("update_v1_extract_message_data");

let preimage = b"account:MessageBuffer";
let mut expected_sighash = [0u8; 8];
expected_sighash.copy_from_slice(&hashv(&[preimage]).to_bytes()[..8]);
Expand All @@ -154,7 +174,7 @@ pub fn update_v1(

// This code, using the offsets in each Account, extracts the various data versions from
// the account. We deduplicate this result because the accumulator expects a set.
message_buffer_accounts
let res = message_buffer_accounts
.map(|(_, account)| {
let data = account.data();
let mut cursor = std::io::Cursor::new(&data);
Expand Down Expand Up @@ -185,11 +205,21 @@ pub fn update_v1(
.collect::<std::result::Result<Vec<_>, std::io::Error>>()?
.into_iter()
.flatten()
.collect()
.collect();

measure.stop();
debug!(
"Accumulator: Extracted message data in {}us",
measure.as_us()
);

res
} else {
Vec::new()
};

let mut measure = Measure::start("create_message_set");

let mut messages = v1_messages;
messages.extend(v2_messages.iter().map(|x| &**x));
messages.sort_unstable();
Expand Down Expand Up @@ -220,11 +250,27 @@ pub fn update_v1(
account
};

measure.stop();
debug!("Accumulator: Created message set in {}us", measure.as_us());

// Generate a Message owned by Wormhole to be sent cross-chain. This short-circuits the
// Wormhole message generation code that would normally be called, but the Guardian
// set filters our messages so this does not pose a security risk.
if let Some(accumulator) = MerkleAccumulator::<Keccak160>::from_set(messages.into_iter()) {
let mut measure = Measure::start("create_accumulator");

let maybe_accumulator = MerkleAccumulator::<Keccak160>::from_set(messages.into_iter());

measure.stop();
debug!("Accumulator: Created accumulator in {}us", measure.as_us());

if let Some(accumulator) = maybe_accumulator {
let mut measure = Measure::start("post_accumulator_attestation");
post_accumulator_attestation(bank, accumulator, ring_index)?;
measure.stop();
debug!(
"Accumulator: Posted accumulator attestation in {}us",
measure.as_us()
);
}

// Write the Account Set into `accumulator_state` so that the hermes application can
Expand All @@ -233,7 +279,14 @@ pub fn update_v1(
"Accumulator: Writing accumulator state to {:?}",
accumulator_account
);

let mut measure = Measure::start("store_account_and_update_capitalization");
bank.store_account_and_update_capitalization(&accumulator_account, &accumulator_data);
measure.stop();
debug!(
"Accumulator: Stored accumulator state in {}us",
measure.as_us()
);

Ok(())
}
Expand Down Expand Up @@ -333,10 +386,30 @@ fn post_accumulator_attestation(
}

pub fn update_v2(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV1> {
let mut measure = Measure::start("update_v2_load_program_accounts");

assert!(
bank.account_indexes_include_key(&*ORACLE_PID),
"Oracle program account index missing"
);

let accounts = bank
.get_program_accounts(&ORACLE_PID, &ScanConfig::new(true))
.get_filtered_indexed_accounts(
&IndexKey::ProgramId(*ORACLE_PID),
|account| account.owner() == &*ORACLE_PID,
&ScanConfig::new(true),
None,
)
.map_err(AccumulatorUpdateErrorV1::GetProgramAccounts)?;

measure.stop();
debug!(
"Accumulator: Loaded oracle program accounts in {}us",
measure.as_us()
);

let mut measure = Measure::start("update_v2_aggregate_price");

let mut any_v1_aggregations = false;
let mut v2_messages = Vec::new();

Expand Down Expand Up @@ -364,5 +437,12 @@ pub fn update_v2(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
}
}

measure.stop();
debug!(
"Accumulator: Aggregated oracle prices in {}us and generated {} messages",
measure.as_us(),
v2_messages.len()
);

update_v1(bank, &v2_messages, any_v1_aggregations)
}
27 changes: 24 additions & 3 deletions runtime/src/bank/pyth_accumulator_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use {
super::pyth_accumulator::MESSAGE_BUFFER_PID,
crate::{
accounts_db::AccountShrinkThreshold,
accounts_index::{
AccountIndex, AccountSecondaryIndexes, AccountSecondaryIndexesIncludeExclude,
},
bank::{
pyth_accumulator::{get_accumulator_keys, ACCUMULATOR_RING_SIZE, ORACLE_PID},
Bank,
Expand All @@ -25,6 +30,7 @@ use {
epoch_schedule::EpochSchedule,
feature::{self, Feature},
feature_set,
genesis_config::GenesisConfig,
hash::hashv,
pubkey::Pubkey,
signature::keypair_from_seed,
Expand All @@ -33,6 +39,21 @@ use {
std::{io::Read, mem::size_of, sync::Arc},
};

fn create_new_bank_for_tests_with_index(genesis_config: &GenesisConfig) -> Bank {
Bank::new_with_config_for_tests(
genesis_config,
AccountSecondaryIndexes {
keys: Some(AccountSecondaryIndexesIncludeExclude {
exclude: false,
keys: [*ORACLE_PID, *MESSAGE_BUFFER_PID].into_iter().collect(),
}),
indexes: [AccountIndex::ProgramId].into_iter().collect(),
},
false,
AccountShrinkThreshold::default(),
)
}

// Create Message Account Bytes
//
// NOTE: This was serialized by hand, but should be replaced with the pythnet-sdk
Expand Down Expand Up @@ -107,7 +128,7 @@ fn test_update_accumulator_sysvar() {
// due to slot 0 having special handling.
let slots_in_epoch = 32;
genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
let mut bank = Bank::new_for_tests(&genesis_config);
let mut bank = create_new_bank_for_tests_with_index(&genesis_config);
bank = new_from_parent(&Arc::new(bank));
bank = new_from_parent(&Arc::new(bank));

Expand Down Expand Up @@ -392,7 +413,7 @@ fn test_update_accumulator_end_of_block() {
// due to slot 0 having special handling.
let slots_in_epoch = 32;
genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
let mut bank = Bank::new_for_tests(&genesis_config);
let mut bank = create_new_bank_for_tests_with_index(&genesis_config);
bank = new_from_parent(&Arc::new(bank));
bank = new_from_parent(&Arc::new(bank));

Expand Down Expand Up @@ -683,7 +704,7 @@ fn test_accumulator_v2(generate_buffers: [bool; 4]) {
// due to slot 0 having special handling.
let slots_in_epoch = 32;
genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
let mut bank = Bank::new_for_tests(&genesis_config);
let mut bank = create_new_bank_for_tests_with_index(&genesis_config);

let generate_price = |seeds, generate_buffers: bool| {
let (price_feed_key, _bump) = Pubkey::find_program_address(&[seeds], &ORACLE_PID);
Expand Down
22 changes: 22 additions & 0 deletions validator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use {
AccountIndex, AccountSecondaryIndexes, AccountSecondaryIndexesIncludeExclude,
AccountsIndexConfig, IndexLimitMb,
},
bank::pyth_accumulator::{MESSAGE_BUFFER_PID, ORACLE_PID},
hardened_unpack::MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
runtime_config::RuntimeConfig,
snapshot_config::SnapshotConfig,
Expand Down Expand Up @@ -3176,6 +3177,10 @@ fn process_account_indexes(matches: &ArgMatches) -> AccountSecondaryIndexes {
})
.collect();

assert(account_indexes.contains(&AccountIndex::ProgramId),
"The indexing should be enabled for program-id accounts. Add the following flag:\n\
--account-index program-id\n");

let account_indexes_include_keys: HashSet<Pubkey> =
values_t!(matches, "account_index_include_key", Pubkey)
.unwrap_or_default()
Expand All @@ -3193,6 +3198,23 @@ fn process_account_indexes(matches: &ArgMatches) -> AccountSecondaryIndexes {
let exclude_keys = !account_indexes_exclude_keys.is_empty();
let include_keys = !account_indexes_include_keys.is_empty();

if include_keys {
if !account_indexes_include_keys.contains(&*ORACLE_PID) || !account_indexes_include_keys.contains(&*MESSAGE_BUFFER_PID) {
panic!(
"The oracle program id and message buffer program id must be included in the account index. Add the following flags\n\
--account-index-include-key {}\n\
--account-index-include-key {}\n",
&*ORACLE_PID, &*MESSAGE_BUFFER_PID
);
}
}

if exclude_keys {
if account_indexes_exclude_keys.contains(&*ORACLE_PID) || account_indexes_exclude_keys.contains(&*MESSAGE_BUFFER_PID) {
panic!("The oracle program id and message buffer program id must *not* be excluded from the account index.");
}
}

let keys = if !account_indexes.is_empty() && (exclude_keys || include_keys) {
let account_indexes_keys = AccountSecondaryIndexesIncludeExclude {
exclude: exclude_keys,
Expand Down