Skip to content

Commit 2a7cebd

Browse files
authored
Batch publish (#313)
* feat: batch publish * chore: add CI 10 * feat: batch publish 2 (wip) * feat: verify that price feed index is set * refactor: add pyth module * feat: integrate pyth-price-publisher * refactor: rename and move get_accumulator_keys * test: make sure batch publish does not apply prices when price_index == 0 * chore: fix format * fix: update deps
1 parent 2eb518a commit 2a7cebd

File tree

12 files changed

+533
-92
lines changed

12 files changed

+533
-92
lines changed

.github/workflows/pyth.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Check Pythnet
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [pyth-v1.14.17]
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v2
12+
- uses: actions-rs/toolchain@v1
13+
with:
14+
profile: minimal
15+
toolchain: 1.60.0
16+
components: clippy
17+
override: true
18+
- name: Install dependencies
19+
run: |
20+
sudo apt-get update
21+
sudo apt-get install -y libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang cmake make libprotobuf-dev
22+
- name: Run tests
23+
run: cargo test -p solana-runtime pyth
24+
clippy:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v2
28+
- uses: actions-rs/toolchain@v1
29+
with:
30+
profile: minimal
31+
toolchain: 1.60.0
32+
components: clippy
33+
override: true
34+
- name: Install dependencies
35+
run: |
36+
sudo apt-get update
37+
sudo apt-get install -y libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang cmake make libprotobuf-dev
38+
- name: Check clippy
39+
run: cargo clippy --bins --tests --examples -- --deny warnings
40+
format:
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@v2
44+
- uses: actions-rs/toolchain@v1
45+
with:
46+
profile: minimal
47+
toolchain: nightly-2022-04-01
48+
components: rustfmt
49+
override: true
50+
- name: Check formatting
51+
run: cargo fmt -- --check

Cargo.lock

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/validator.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ use {
7474
accounts_db::{AccountShrinkThreshold, AccountsDbConfig},
7575
accounts_index::AccountSecondaryIndexes,
7676
accounts_update_notifier_interface::AccountsUpdateNotifier,
77-
bank::{pyth_accumulator, Bank},
77+
bank::{pyth, Bank},
7878
bank_forks::BankForks,
7979
commitment::BlockCommitmentCache,
8080
cost_model::CostModel,
@@ -1521,14 +1521,8 @@ fn load_blockstore(
15211521
}
15221522
}
15231523

1524-
for (key_name, pk_res) in pyth_accumulator::get_accumulator_keys() {
1525-
match pk_res {
1526-
Ok(pk) => info!("Accumulator {}: {}", key_name, pk),
1527-
Err(err) => {
1528-
error!("Failed to get Accumulator {}: {:?}", key_name, err);
1529-
std::process::abort();
1530-
}
1531-
}
1524+
for (key_name, pk) in pyth::get_pyth_keys() {
1525+
info!("Pyth key {}: {}", key_name, pk);
15321526
}
15331527

15341528
leader_schedule_cache.set_fixed_leader_schedule(config.fixed_leader_schedule.clone());

runtime/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ num-traits = { version = "0.2" }
3535
num_cpus = "1.13.1"
3636
once_cell = "1.12.0"
3737
ouroboros = "0.15.0"
38-
pyth-oracle = { git = "https://github.com/pyth-network/pyth-client", tag = "oracle-v2.33.0", features = ["library"] }
38+
pyth-oracle = { git = "https://github.com/pyth-network/pyth-client", rev = "256b57", features = ["library"] }
3939
pythnet-sdk = { git = "https://github.com/pyth-network/pyth-crosschain", version = "1.13.6", rev = "33f901aa45f4f0005aa5a84a1479b78ca9033074" }
40+
pyth-price-publisher = { git = "https://github.com/pyth-network/pyth-crosschain", branch = "add-publisher-program" }
4041
rand = "0.7.0"
4142
rayon = "1.5.3"
4243
regex = "1.5.6"

runtime/src/bank.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,7 @@ mod builtin_programs;
198198
mod sysvar_cache;
199199
mod transaction_account_state_info;
200200

201-
pub mod pyth_accumulator;
202-
203-
#[cfg(test)]
204-
mod pyth_accumulator_tests;
201+
pub mod pyth;
205202

206203
pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
207204

@@ -1410,7 +1407,7 @@ impl Bank {
14101407
// state before the accumulator is used. bank is in a fully
14111408
// updated state before the accumulator is used.
14121409
if !accumulator_moved_to_end_of_block {
1413-
pyth_accumulator::update_accumulator(&bank);
1410+
pyth::accumulator::update_accumulator(&bank);
14141411
}
14151412

14161413
bank
@@ -1796,7 +1793,7 @@ impl Bank {
17961793
// the accumulator sysvar updates. sysvars are in a fully updated
17971794
// state before the accumulator sysvar updates.
17981795
if !accumulator_moved_to_end_of_block {
1799-
pyth_accumulator::update_accumulator(&new);
1796+
pyth::accumulator::update_accumulator(&new);
18001797
}
18011798
});
18021799

@@ -3238,7 +3235,7 @@ impl Bank {
32383235
// other tasks when freezing to avoid any conflicts.
32393236
if accumulator_moved_to_end_of_block {
32403237
let mut measure = Measure::start("accumulator");
3241-
pyth_accumulator::update_accumulator(self);
3238+
pyth::accumulator::update_accumulator(self);
32423239
measure.stop();
32433240

32443241
debug!(

runtime/src/bank/pyth_accumulator.rs renamed to runtime/src/bank/pyth/accumulator.rs

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use {
2-
super::Bank,
3-
crate::accounts_index::{IndexKey, ScanConfig, ScanError},
2+
super::batch_publish,
3+
crate::{
4+
accounts_index::{IndexKey, ScanConfig, ScanError},
5+
bank::Bank,
6+
},
47
byteorder::{LittleEndian, ReadBytesExt},
8+
itertools::Itertools,
59
log::*,
610
pyth_oracle::validator::AggregationError,
711
pythnet_sdk::{
@@ -17,7 +21,10 @@ use {
1721
hash::hashv,
1822
pubkey::Pubkey,
1923
},
20-
std::env::{self, VarError},
24+
std::{
25+
collections::HashMap,
26+
env::{self, VarError},
27+
},
2128
};
2229

2330
pub const ACCUMULATOR_RING_SIZE: u32 = 10_000;
@@ -51,6 +58,13 @@ lazy_static! {
5158
.parse()
5259
.unwrap(),
5360
);
61+
pub static ref BATCH_PUBLISH_PID: Pubkey = env_pubkey_or(
62+
"BATCH_PUBLISH_PID",
63+
// TODO: replace with real program id
64+
"FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epA"
65+
.parse()
66+
.unwrap(),
67+
);
5468
}
5569

5670
/// Accumulator specific error type. It would be nice to use `transaction::Error` but it does
@@ -116,25 +130,6 @@ fn env_pubkey_or(var: &str, default: Pubkey) -> Pubkey {
116130
}
117131
}
118132

119-
/// Get all accumulator related pubkeys from environment variables
120-
/// or return default if the variable is not set.
121-
pub fn get_accumulator_keys() -> Vec<(
122-
&'static str,
123-
std::result::Result<Pubkey, AccumulatorUpdateErrorV1>,
124-
)> {
125-
vec![
126-
("MESSAGE_BUFFER_PID", Ok(*MESSAGE_BUFFER_PID)),
127-
("ACCUMULATOR_EMITTER_ADDR", Ok(*ACCUMULATOR_EMITTER_ADDR)),
128-
("ACCUMULATOR_SEQUENCE_ADDR", Ok(*ACCUMULATOR_SEQUENCE_ADDR)),
129-
("WORMHOLE_PID", Ok(*WORMHOLE_PID)),
130-
("ORACLE_PID", Ok(*ORACLE_PID)),
131-
(
132-
"STAKE_CAPS_PARAMETERS_ADDR",
133-
Ok(*STAKE_CAPS_PARAMETERS_ADDR),
134-
),
135-
]
136-
}
137-
138133
pub fn update_v1(
139134
bank: &Bank,
140135
v2_messages: &[Vec<u8>],
@@ -427,21 +422,37 @@ pub fn update_v2(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
427422
v2_messages.push(publisher_stake_caps_message);
428423
}
429424

430-
let mut measure = Measure::start("update_v2_aggregate_price");
425+
let mut measure = Measure::start("extract_batch_publish_prices");
426+
let mut new_prices = batch_publish::extract_batch_publish_prices(bank).unwrap_or_else(|err| {
427+
warn!("extract_batch_publish_prices failed: {}", err);
428+
HashMap::new()
429+
});
430+
measure.stop();
431+
debug!("batch publish: loaded prices in {}us", measure.as_us());
431432

433+
let mut measure = Measure::start("update_v2_aggregate_price");
432434
for (pubkey, mut account) in accounts {
433435
let mut price_account_data = account.data().to_owned();
436+
let price_account =
437+
match pyth_oracle::validator::checked_load_price_account_mut(&mut price_account_data) {
438+
Ok(data) => data,
439+
Err(_err) => {
440+
continue;
441+
}
442+
};
443+
444+
let mut need_save =
445+
batch_publish::apply_published_prices(price_account, &mut new_prices, bank.slot());
434446

435447
// Perform Accumulation
436448
match pyth_oracle::validator::aggregate_price(
437449
bank.slot(),
438450
bank.clock().unix_timestamp,
439451
&pubkey.to_bytes().into(),
440-
&mut price_account_data,
452+
price_account,
441453
) {
442454
Ok(messages) => {
443-
account.set_data(price_account_data);
444-
bank.store_account_and_update_capitalization(&pubkey, &account);
455+
need_save = true;
445456
v2_messages.extend(messages);
446457
}
447458
Err(err) => match err {
@@ -451,6 +462,16 @@ pub fn update_v2(bank: &Bank) -> std::result::Result<(), AccumulatorUpdateErrorV
451462
}
452463
},
453464
}
465+
if need_save {
466+
account.set_data(price_account_data);
467+
bank.store_account_and_update_capitalization(&pubkey, &account);
468+
}
469+
}
470+
if !new_prices.is_empty() {
471+
warn!(
472+
"pyth batch publish: missing price feed accounts for indexes: {}",
473+
new_prices.keys().join(", ")
474+
);
454475
}
455476

456477
measure.stop();

0 commit comments

Comments
 (0)