diff --git a/program/rust/src/processor/upd_price.rs b/program/rust/src/processor/upd_price.rs index 5edf7a8e..cd9e9e07 100644 --- a/program/rust/src/processor/upd_price.rs +++ b/program/rust/src/processor/upd_price.rs @@ -131,6 +131,7 @@ pub fn upd_price( let mut publisher_index: usize = 0; let latest_aggregate_price: PriceInfo; let slots_since_last_update: u64; + let noninitial_price_update_after_program_upgrade: bool; // The price_data borrow happens in a scope because it must be // dropped before we borrow again as raw data pointer for the C @@ -154,6 +155,13 @@ pub fn upd_price( // We use last_slot_ to calculate slots_since_last_update. This is because last_slot_ is updated after the aggregate price is updated successfully. slots_since_last_update = clock.slot - price_data.last_slot_; + // Check if the program upgrade has happened in the current slot and aggregate price has been updated, if so, use the old logic to update twap/twac/price_cumulative. + // This is to ensure that twap/twac/price_cumulative are calculated correctly during the migration. + // We check if prev_twap_.denom_ is == 0 because when the program upgrade has happened, denom_ is initialized to 0 and it can only stay the same or increase while numer_ can be negative if prices are negative. + // And we check if slots_since_last_update == 0 to check if the aggregate price has been updated in the current slot. + noninitial_price_update_after_program_upgrade = + price_data.prev_twap_.denom_ == 0 && slots_since_last_update == 0; + // We assign the current aggregate price to latest_aggregate_price before calling c_upd_aggregate because // c_upd_aggregate directly modifies the memory of price_data.agg_ to update its values. This is crucial for // comparisons or operations that rely on the aggregate price state before the update such as slots_since_last_update. @@ -197,14 +205,18 @@ pub fn upd_price( } let updated = unsafe { - // NOTE: c_upd_aggregate must use a raw pointer to price - // data. Solana's `.borrow_*` methods require exclusive - // access, i.e. no other borrow can exist for the account. - c_upd_aggregate( - price_account.try_borrow_mut_data()?.as_mut_ptr(), - clock.slot, - clock.unix_timestamp, - ) + if noninitial_price_update_after_program_upgrade { + false + } else { + // NOTE: c_upd_aggregate must use a raw pointer to price + // data. Solana's `.borrow_*` methods require exclusive + // access, i.e. no other borrow can exist for the account. + c_upd_aggregate( + price_account.try_borrow_mut_data()?.as_mut_ptr(), + clock.slot, + clock.unix_timestamp, + ) + } }; // If the aggregate was successfully updated, calculate the difference and update TWAP. @@ -216,11 +228,7 @@ pub fn upd_price( let mut price_data = load_checked::(price_account, cmd_args.header.version)?; - // Check if the program upgrade has happened in the current slot and aggregate price has been updated, if so, use the old logic to update twap/twac/price_cumulative. - // This is to ensure that twap/twac/price_cumulative are calculated correctly during the migration. - // We check if prev_twap_.denom_ is == 0 because when the program upgrade has happened, denom_ is initialized to 0 and it can only stay the same or increase while numer_ can be negative if prices are negative. - // And we check if slots_since_last_update == 0 to check if the aggregate price has been updated in the current slot. - if !(price_data.prev_twap_.denom_ == 0 && slots_since_last_update == 0) { + if !(noninitial_price_update_after_program_upgrade) { // 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 diff --git a/program/rust/src/tests/test_upd_price.rs b/program/rust/src/tests/test_upd_price.rs index f0f59a2f..3481f5de 100644 --- a/program/rust/src/tests/test_upd_price.rs +++ b/program/rust/src/tests/test_upd_price.rs @@ -299,7 +299,7 @@ fn test_upd_price() { assert_eq!(price_data.comp_[0].latest_.conf_, 1); assert_eq!(price_data.comp_[0].latest_.pub_slot_, 7); assert_eq!(price_data.comp_[0].latest_.status_, PC_STATUS_TRADING); - assert_eq!(price_data.valid_slot_, 7); + assert_eq!(price_data.valid_slot_, 6); assert_eq!(price_data.agg_.pub_slot_, 8); assert_eq!(price_data.agg_.price_, -100); assert_eq!(price_data.agg_.status_, PC_STATUS_TRADING);