Skip to content

Commit acba47f

Browse files
authored
feat: support zero ci (#429)
* feat: support no default accumulator v2 we have no default accumulator v2 in Pythtest conformance * feat: support zero confirmation for aggregation * fix: update pre-commit action version in ci * fix: correct a typo on the ad_price and fix test script * fix: update dokcer workflow to compy files correctly
1 parent e4d5f1d commit acba47f

File tree

16 files changed

+298
-31
lines changed

16 files changed

+298
-31
lines changed

.github/workflows/check-fomatting.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ jobs:
1616
profile: minimal
1717
toolchain: nightly-2023-03-01
1818
components: rustfmt, clippy
19-
- uses: pre-commit/action@v2.0.3
19+
- uses: pre-commit/action@v3.0.0

.github/workflows/docker.yaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ jobs:
6161
run : |
6262
docker create -ti --name container "${DOCKER_IMAGE}" bash
6363
docker cp container:/home/pyth/pyth-client/target/pyth/pythnet/pyth_oracle_pythnet.so .
64+
docker cp container:/home/pyth/pyth-client/target/pyth/pythnet/pyth_oracle_pythnet_no_accumulator_v2.so .
6465
docker rm -f container
65-
66+
6667
- name : Publish Pythnet binary
6768
if : env.IS_ORACLE_RELEASE == 'true'
6869
uses: svenstaro/upload-release-action@133984371c30d34e38222a64855679a414cb7575
@@ -72,6 +73,15 @@ jobs:
7273
asset_name: pyth_oracle_pythnet.so
7374
tag: ${{ github.ref }}
7475

76+
- name : Publish Pythnet No Default Accumulator v2 binary
77+
if : env.IS_ORACLE_RELEASE == 'true'
78+
uses: svenstaro/upload-release-action@133984371c30d34e38222a64855679a414cb7575
79+
with:
80+
repo_token: ${{ secrets.GITHUB_TOKEN }}
81+
file: ./pyth_oracle_pythnet_no_accumulator_v2.so
82+
asset_name: pyth_oracle_pythnet_no_accumulator_v2.so
83+
tag: ${{ github.ref }}
84+
7585
pinning:
7686
runs-on: ubuntu-latest
7787
steps:

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program/c/src/oracle/oracle.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,9 @@ typedef struct pc_price
193193
uint8_t min_pub_; // min publishers for valid price
194194
int8_t message_sent_; // flag to indicate if the current aggregate price has been sent as a message to the message buffer, 0 if not sent, 1 if sent
195195
uint8_t max_latency_; // configurable max latency in slots between send and receive
196-
int8_t drv3_; // space for future derived values
197-
int32_t drv4_; // space for future derived values
196+
uint8_t flags; // Various bit flags. See PriceAccountFlags rust struct for more details.
197+
// 0: ACCUMULATOR_V2, 1: MESSAGE_BUFFER_CLEARED 2: ALLOW_ZERO_CI
198+
uint32_t feed_index; // Globally unique feed index for this price feed
198199
pc_pub_key_t prod_; // product id/ref-account
199200
pc_pub_key_t next_; // next price account in list
200201
uint64_t prev_slot_; // valid slot of previous aggregate with TRADING status

program/c/src/oracle/upd_aggregate.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ static inline bool upd_aggregate( pc_price_t *ptr, uint64_t slot, int64_t timest
155155
uint32_t numv = 0;
156156
uint32_t nprcs = (uint32_t)0;
157157
int64_t prcs[ PC_NUM_COMP * 3 ]; // ~0.75KiB for current PC_NUM_COMP (FIXME: DOUBLE CHECK THIS FITS INTO STACK FRAME LIMIT)
158+
bool allow_zero_ci = (ptr->flags & 0x4) != 0;
159+
158160
for ( uint32_t i = 0; i != ptr->num_; ++i ) {
159161
pc_price_comp_t *iptr = &ptr->comp_[i];
160162
// copy contributing price to aggregate snapshot
@@ -165,9 +167,10 @@ static inline bool upd_aggregate( pc_price_t *ptr, uint64_t slot, int64_t timest
165167
int64_t conf = ( int64_t )( iptr->agg_.conf_ );
166168
int64_t max_latency = ptr->max_latency_ ? ptr->max_latency_ : PC_MAX_SEND_LATENCY;
167169
if ( iptr->agg_.status_ == PC_STATUS_TRADING &&
168-
// No overflow for INT64_MIN+conf or INT64_MAX-conf as 0 < conf < INT64_MAX
169-
// These checks ensure that price - conf and price + conf do not overflow.
170-
(int64_t)0 < conf && (INT64_MIN + conf) <= price && price <= (INT64_MAX-conf) &&
170+
// Only accept confidence of zero if the flag is set
171+
(allow_zero_ci || conf > 0) &&
172+
// these checks ensure that price - conf and price + conf do not overflow.
173+
(INT64_MIN + conf) <= price && price <= (INT64_MAX-conf) &&
171174
// slot_diff is implicitly >= 0 due to the check in Rust code ensuring publishing_slot is always less than or equal to the current slot.
172175
slot_diff <= max_latency ) {
173176
numv += 1;
@@ -201,10 +204,9 @@ static inline bool upd_aggregate( pc_price_t *ptr, uint64_t slot, int64_t timest
201204
// use the larger of the left and right confidences
202205
agg_conf = agg_conf_right > agg_conf_left ? agg_conf_right : agg_conf_left;
203206

204-
// if the confidences end up at zero, we abort
205-
// this is paranoia as it is currently not possible when nprcs>2 and
206-
// positive confidences given the current pricing model
207-
if( agg_conf <= (int64_t)0 ) {
207+
// when zero CI is not allowed, the confidence should not be zero.
208+
// and this check is not necessary, but we do it anyway to be safe.
209+
if( (!allow_zero_ci) && agg_conf <= (int64_t)0 ) {
208210
ptr->agg_.status_ = PC_STATUS_UNKNOWN;
209211
return false;
210212
}

program/rust/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-oracle"
3-
version = "2.34.0"
3+
version = "2.35.0"
44
edition = "2021"
55
license = "Apache 2.0"
66
publish = false
@@ -45,6 +45,7 @@ time = "=0.3.7"
4545
check = [] # Skips make build in build.rs, use with cargo-clippy and cargo-check
4646
debug = []
4747
library = ["solana-sdk"]
48+
no-default-accumulator-v2 = []
4849

4950
[lib]
5051
crate-type = ["cdylib", "lib"]

program/rust/src/accounts/price.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ mod price_pythnet {
108108
/// If unset, the program will remove old messages from its message buffer account
109109
/// and set this flag.
110110
const MESSAGE_BUFFER_CLEARED = 0b10;
111+
/// If set, the program allows publishing of zero confidence interval updates.
112+
const ALLOW_ZERO_CI = 0b100;
111113
}
112114
}
113115

program/rust/src/processor.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ mod upd_product;
4141

4242
#[cfg(test)]
4343
pub use add_publisher::{
44+
ALLOW_ZERO_CI,
4445
DISABLE_ACCUMULATOR_V2,
4546
ENABLE_ACCUMULATOR_V2,
47+
FORBID_ZERO_CI,
4648
};
4749
use solana_program::{
4850
program_error::ProgramError,

program/rust/src/processor/add_price.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,12 @@ pub fn add_price(
8484
price_data.next_price_account = product_data.first_price_account;
8585
price_data.min_pub_ = PRICE_ACCOUNT_DEFAULT_MIN_PUB;
8686
price_data.feed_index = reserve_new_price_feed_index(permissions_account)?;
87-
price_data
88-
.flags
89-
.insert(PriceAccountFlags::ACCUMULATOR_V2 | PriceAccountFlags::MESSAGE_BUFFER_CLEARED);
87+
88+
if !cfg!(feature = "no-default-accumulator-v2") {
89+
price_data
90+
.flags
91+
.insert(PriceAccountFlags::ACCUMULATOR_V2 | PriceAccountFlags::MESSAGE_BUFFER_CLEARED);
92+
}
9093

9194
product_data.first_price_account = *price_account.key;
9295

program/rust/src/processor/add_publisher.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ pub const ENABLE_ACCUMULATOR_V2: [u8; 32] = [
4040
pub const DISABLE_ACCUMULATOR_V2: [u8; 32] = [
4141
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
4242
];
43+
pub const ALLOW_ZERO_CI: [u8; 32] = [
44+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
45+
];
46+
pub const FORBID_ZERO_CI: [u8; 32] = [
47+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
48+
];
4349

4450
/// Add publisher to symbol account
4551
// account[0] funding account [signer writable]
@@ -73,18 +79,23 @@ pub fn add_publisher(
7379

7480
let mut price_data = load_checked::<PriceAccount>(price_account, cmd_args.header.version)?;
7581

82+
// Hack: we use add_publisher instruction to configure the price feeds for some operations.
83+
// This is mostly because we are constrained on contract size and can't add separate
84+
// instructions for these operations.
7685
if cmd_args.publisher == Pubkey::from(ENABLE_ACCUMULATOR_V2) {
77-
// Hack: we use add_publisher instruction to configure the `ACCUMULATOR_V2` flag. Using a new
78-
// instruction would be cleaner but it would require more work in the tooling.
79-
// These special cases can be removed along with the v1 aggregation code once the transition
80-
// is complete.
8186
price_data.flags.insert(PriceAccountFlags::ACCUMULATOR_V2);
8287
return Ok(());
8388
} else if cmd_args.publisher == Pubkey::from(DISABLE_ACCUMULATOR_V2) {
8489
price_data
8590
.flags
8691
.remove(PriceAccountFlags::ACCUMULATOR_V2 | PriceAccountFlags::MESSAGE_BUFFER_CLEARED);
8792
return Ok(());
93+
} else if cmd_args.publisher == Pubkey::from(ALLOW_ZERO_CI) {
94+
price_data.flags.insert(PriceAccountFlags::ALLOW_ZERO_CI);
95+
return Ok(());
96+
} else if cmd_args.publisher == Pubkey::from(FORBID_ZERO_CI) {
97+
price_data.flags.remove(PriceAccountFlags::ALLOW_ZERO_CI);
98+
return Ok(());
8899
}
89100

90101
if price_data.num_ >= PC_NUM_COMP {

0 commit comments

Comments
 (0)