From b8f34844a3b6c751ba1b457d399f188b483b708c Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Wed, 3 Apr 2024 13:31:44 +0900 Subject: [PATCH] add guard for first price update after deployment --- program/rust/src/processor/upd_price.rs | 28 ++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/program/rust/src/processor/upd_price.rs b/program/rust/src/processor/upd_price.rs index ba4d680a..15117e8d 100644 --- a/program/rust/src/processor/upd_price.rs +++ b/program/rust/src/processor/upd_price.rs @@ -165,7 +165,6 @@ pub fn upd_price( )?; } - // If the price update is the first in the slot and the aggregate is trading, update the previous slot, price, conf, and timestamp. let slots_since_last_update = clock.slot - latest_aggregate_price.pub_slot_; // Extend the scope of the mutable borrow of price_data @@ -186,6 +185,7 @@ pub fn upd_price( publisher_price.pub_slot_ = cmd_args.publishing_slot; } + // If the price update is the first in the slot and the aggregate is trading, update the previous slot, price, conf, and timestamp. if slots_since_last_update > 0 && latest_aggregate_price.status_ == PC_STATUS_TRADING { price_data.prev_slot_ = price_data.agg_.pub_slot_; price_data.prev_price_ = price_data.agg_.price_; @@ -213,8 +213,30 @@ pub fn upd_price( { let mut price_data = load_checked::(price_account, cmd_args.header.version)?; - // check if its the first price update in the slot - if slots_since_last_update > 0 { + + // Check if this is the first update by checking if previous values are uninitialized. + // PriceEma implements Zeroable trait, so they are initialized to 0 and we check for that to determine if they are uninitialized. + let is_prev_twap_uninitialized = price_data.prev_twap_.val_ == 0 + && price_data.prev_twap_.numer_ == 0 + && price_data.prev_twap_.denom_ == 0; + let is_prev_twac_uninitialized = price_data.prev_twac_.val_ == 0 + && price_data.prev_twac_.numer_ == 0 + && price_data.prev_twac_.denom_ == 0; + let is_prev_price_cumulative_uninitialized = price_data.prev_price_cumulative.price + == 0 + && price_data.prev_price_cumulative.conf == 0 + && price_data.prev_price_cumulative.num_down_slots == 0 + && price_data.prev_price_cumulative.unused == 0; + let is_prev_ema_and_twap_uninitialized = is_prev_twap_uninitialized + && is_prev_twac_uninitialized + && is_prev_price_cumulative_uninitialized; + + // Multiple price updates may occur within the same slot. Updates within the same slot will + // use the previously calculated values (prev_twap, prev_twac, and prev_price_cumulative) + // from the last successful aggregated price update as their basis for recalculation. This + // ensures that each update within a slot builds upon the last and not the twap/twac/price_cumulative + // that is calculated right after the publishers' individual price updates. + if slots_since_last_update > 0 || is_prev_ema_and_twap_uninitialized { price_data.prev_twap_ = price_data.twap_; price_data.prev_twac_ = price_data.twac_; price_data.prev_price_cumulative = price_data.price_cumulative;