浏览代码

fix compilation errors

Daniel Chew 8 月之前
父节点
当前提交
005cf2c086

+ 137 - 138
apps/argus/src/api.rs

@@ -1,8 +1,5 @@
 use {
-    crate::{
-        chain::reader::{BlockNumber, BlockStatus, PulseReader},
-        state::HashChainState,
-    },
+    crate::chain::reader::{BlockStatus, PulseReader},
     anyhow::Result,
     axum::{
         body::Body,
@@ -21,14 +18,14 @@ use {
     tokio::sync::RwLock,
     url::Url,
 };
-pub use {chain_ids::*, index::*, live::*, metrics::*, ready::*, price_updates::*};
+pub use {chain_ids::*, index::*, live::*, metrics::*, price_updates::*, ready::*};
 
 mod chain_ids;
 mod index;
 mod live;
 mod metrics;
-mod ready;
 mod price_updates;
+mod ready;
 
 pub type ChainId = String;
 
@@ -75,20 +72,15 @@ impl ApiState {
     }
 }
 
-/// The state of the randomness service for a single blockchain.
+/// The state of the price update service for a single blockchain.
 #[derive(Clone)]
 pub struct BlockchainState {
     /// The chain id for this blockchain, useful for logging
     pub id: ChainId,
-    /// The hash chain(s) required to serve random numbers for this blockchain
-    pub state: Arc<HashChainState>,
     /// The contract that the server is fulfilling requests for.
     pub contract: Arc<dyn PulseReader>,
     /// The address of the provider that this server is operating for.
     pub provider_address: Address,
-    /// The server will wait for this many block confirmations of a request before revealing
-    /// the random number.
-    pub reveal_delay_blocks: BlockNumber,
     /// The BlockStatus of the block that is considered to be confirmed on the blockchain.
     /// For eg., Finalized, Safe
     pub confirmed_block_status: BlockStatus,
@@ -99,14 +91,11 @@ pub enum RestError {
     InvalidSequenceNumber,
     /// The caller passed an unsupported chain id
     InvalidChainId,
-    /// The caller requested a random value that can't currently be revealed (because it
-    /// hasn't been committed to on-chain)
+    /// The caller requested price updates that can't currently be provided (because they
+    /// haven't been committed to on-chain)
     NoPendingRequest,
-    /// The request exists, but the server is waiting for more confirmations (more blocks
-    /// to be mined) before revealing the random number.
-    PendingConfirmation,
     /// The server cannot currently communicate with the blockchain, so is not able to verify
-    /// which random values have been requested.
+    /// which price updates have been requested.
     TemporarilyUnavailable,
     /// A catch-all error for all other types of errors that could occur during processing.
     Unknown,
@@ -125,13 +114,8 @@ impl IntoResponse for RestError {
             }
             RestError::NoPendingRequest => (
                 StatusCode::FORBIDDEN,
-                "The request with the given sequence number has not been made yet, or the random value has already been revealed on chain.",
+                "The request with the given sequence number has not been made yet, or the price updates have already been provided on chain.",
             ).into_response(),
-            RestError::PendingConfirmation => (
-                StatusCode::FORBIDDEN,
-                "The request needs additional confirmations before the random value can be retrieved. Try your request again later.",
-            )
-                .into_response(),
             RestError::TemporarilyUnavailable => (
                 StatusCode::SERVICE_UNAVAILABLE,
                 "This service is temporarily unavailable",
@@ -154,8 +138,8 @@ pub fn routes(state: ApiState) -> Router<(), Body> {
         .route("/ready", get(ready))
         .route("/v1/chains", get(chain_ids))
         .route(
-            "/v1/chains/:chain_id/revelations/:sequence",
-            get(revelation),
+            "/v1/chains/:chain_id/price-updates/:sequence",
+            get(price_update),
         )
         .with_state(state)
 }
@@ -174,13 +158,12 @@ pub fn get_register_uri(base_uri: &str, chain_id: &str) -> Result<String> {
 mod test {
     use {
         crate::{
-            api::{self, ApiState, BinaryEncoding, Blob, BlockchainState, GetRandomValueResponse},
+            api::{self, ApiState, BlockchainState},
             chain::reader::{mock::MockPulseReader, BlockStatus},
-            state::{HashChainState, PebbleHashChain},
         },
         axum::http::StatusCode,
         axum_test::{TestResponse, TestServer},
-        ethers::prelude::Address,
+        ethers::prelude::{Address, U256},
         lazy_static::lazy_static,
         prometheus_client::registry::Registry,
         std::{collections::HashMap, sync::Arc},
@@ -190,16 +173,6 @@ mod test {
     const PROVIDER: Address = Address::zero();
     lazy_static! {
         static ref OTHER_PROVIDER: Address = Address::from_low_u64_be(1);
-        // Note: these chains are immutable. They are wrapped in Arc because we need Arcs to
-        // initialize the BlockchainStates below, but they aren't cloneable (nor do they need to be cloned).
-        static ref ETH_CHAIN: Arc<HashChainState> = Arc::new(HashChainState::from_chain_at_offset(
-            0,
-            PebbleHashChain::new([0u8; 32], 1000, 1),
-        ));
-        static ref AVAX_CHAIN: Arc<HashChainState> = Arc::new(HashChainState::from_chain_at_offset(
-            100,
-            PebbleHashChain::new([1u8; 32], 1000, 1),
-        ));
     }
 
     async fn test_server() -> (TestServer, Arc<MockPulseReader>, Arc<MockPulseReader>) {
@@ -207,10 +180,8 @@ mod test {
 
         let eth_state = BlockchainState {
             id: "ethereum".into(),
-            state: ETH_CHAIN.clone(),
             contract: eth_read.clone(),
             provider_address: PROVIDER,
-            reveal_delay_blocks: 1,
             confirmed_block_status: BlockStatus::Latest,
         };
 
@@ -220,10 +191,8 @@ mod test {
 
         let avax_state = BlockchainState {
             id: "avalanche".into(),
-            state: AVAX_CHAIN.clone(),
             contract: avax_read.clone(),
             provider_address: PROVIDER,
-            reveal_delay_blocks: 2,
             confirmed_block_status: BlockStatus::Latest,
         };
 
@@ -248,105 +217,145 @@ mod test {
     }
 
     #[tokio::test]
-    async fn test_revelation() {
+    async fn test_price_updates() {
         let (server, eth_contract, avax_contract) = test_server().await;
+        let empty_price_ids: Vec<[u8; 32]> = vec![];
+        let callback_gas_limit = U256::from(100000);
+        let publish_time = U256::from(1000);
 
-        // Can't access a revelation if it hasn't been requested
+        // Can't access price updates if they haven't been requested
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/0",
+            "/v1/chains/ethereum/price-updates/0",
             StatusCode::FORBIDDEN,
         )
         .await;
 
-        // Once someone requests the number, then it is accessible
-        eth_contract.insert(PROVIDER, 0, 1, false);
-        let response =
-            get_and_assert_status(&server, "/v1/chains/ethereum/revelations/0", StatusCode::OK)
-                .await;
-        response.assert_json(&GetRandomValueResponse {
-            value: Blob::new(BinaryEncoding::Hex, ETH_CHAIN.reveal(0).unwrap()),
-        });
+        // Once someone requests the price updates, then they are accessible
+        eth_contract.insert(
+            PROVIDER,
+            0,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        get_and_assert_status(
+            &server,
+            "/v1/chains/ethereum/price-updates/0",
+            StatusCode::OK,
+        )
+        .await;
 
         // Each chain and provider has its own set of requests
-        eth_contract.insert(PROVIDER, 100, 1, false);
-        eth_contract.insert(*OTHER_PROVIDER, 101, 1, false);
-        eth_contract.insert(PROVIDER, 102, 1, false);
-        avax_contract.insert(PROVIDER, 102, 1, false);
-        avax_contract.insert(PROVIDER, 103, 1, false);
-        avax_contract.insert(*OTHER_PROVIDER, 104, 1, false);
-
-        let response = get_and_assert_status(
+        eth_contract.insert(
+            PROVIDER,
+            100,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        eth_contract.insert(
+            *OTHER_PROVIDER,
+            101,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        eth_contract.insert(
+            PROVIDER,
+            102,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        avax_contract.insert(
+            PROVIDER,
+            102,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        avax_contract.insert(
+            PROVIDER,
+            103,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        avax_contract.insert(
+            *OTHER_PROVIDER,
+            104,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+
+        get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/100",
+            "/v1/chains/ethereum/price-updates/100",
             StatusCode::OK,
         )
         .await;
-        response.assert_json(&GetRandomValueResponse {
-            value: Blob::new(BinaryEncoding::Hex, ETH_CHAIN.reveal(100).unwrap()),
-        });
 
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/101",
+            "/v1/chains/ethereum/price-updates/101",
             StatusCode::FORBIDDEN,
         )
         .await;
-        let response = get_and_assert_status(
+
+        get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/102",
+            "/v1/chains/ethereum/price-updates/102",
             StatusCode::OK,
         )
         .await;
-        response.assert_json(&GetRandomValueResponse {
-            value: Blob::new(BinaryEncoding::Hex, ETH_CHAIN.reveal(102).unwrap()),
-        });
+
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/103",
+            "/v1/chains/ethereum/price-updates/103",
             StatusCode::FORBIDDEN,
         )
         .await;
+
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/104",
+            "/v1/chains/ethereum/price-updates/104",
             StatusCode::FORBIDDEN,
         )
         .await;
 
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/100",
+            "/v1/chains/avalanche/price-updates/100",
             StatusCode::FORBIDDEN,
         )
         .await;
+
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/101",
+            "/v1/chains/avalanche/price-updates/101",
             StatusCode::FORBIDDEN,
         )
         .await;
-        let response = get_and_assert_status(
+
+        get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/102",
+            "/v1/chains/avalanche/price-updates/102",
             StatusCode::OK,
         )
         .await;
-        response.assert_json(&GetRandomValueResponse {
-            value: Blob::new(BinaryEncoding::Hex, AVAX_CHAIN.reveal(102).unwrap()),
-        });
-        let response = get_and_assert_status(
+
+        get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/103",
+            "/v1/chains/avalanche/price-updates/103",
             StatusCode::OK,
         )
         .await;
-        response.assert_json(&GetRandomValueResponse {
-            value: Blob::new(BinaryEncoding::Hex, AVAX_CHAIN.reveal(103).unwrap()),
-        });
+
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/104",
+            "/v1/chains/avalanche/price-updates/104",
             StatusCode::FORBIDDEN,
         )
         .await;
@@ -354,97 +363,87 @@ mod test {
         // Bad chain ids fail
         get_and_assert_status(
             &server,
-            "/v1/chains/not_a_chain/revelations/0",
+            "/v1/chains/not_a_chain/price-updates/0",
             StatusCode::BAD_REQUEST,
         )
         .await;
-
-        // Requesting a number that has a request, but isn't in the HashChainState also fails.
-        // (Note that this shouldn't happen in normal operation)
-        get_and_assert_status(
-            &server,
-            "/v1/chains/avalanche/revelations/99",
-            StatusCode::FORBIDDEN,
-        )
-        .await;
-        avax_contract.insert(PROVIDER, 99, 1, false);
-        get_and_assert_status(
-            &server,
-            "/v1/chains/avalanche/revelations/99",
-            StatusCode::INTERNAL_SERVER_ERROR,
-        )
-        .await;
     }
 
     #[tokio::test]
-    async fn test_revelation_confirmation_delay() {
+    async fn test_price_update_confirmation_delay() {
         let (server, eth_contract, avax_contract) = test_server().await;
+        let empty_price_ids: Vec<[u8; 32]> = vec![];
+        let callback_gas_limit = U256::from(100000);
+        let publish_time = U256::from(1000);
 
-        eth_contract.insert(PROVIDER, 0, 10, false);
-        eth_contract.insert(PROVIDER, 1, 11, false);
-        eth_contract.insert(PROVIDER, 2, 12, false);
-
-        avax_contract.insert(PROVIDER, 100, 10, false);
-        avax_contract.insert(PROVIDER, 101, 11, false);
-
-        eth_contract.set_block_number(10);
-        avax_contract.set_block_number(10);
-
+        // No requests yet, so all requests should be forbidden
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/0",
+            "/v1/chains/ethereum/price-updates/0",
             StatusCode::FORBIDDEN,
         )
         .await;
 
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/100",
+            "/v1/chains/avalanche/price-updates/100",
             StatusCode::FORBIDDEN,
         )
         .await;
 
-        eth_contract.set_block_number(11);
-        avax_contract.set_block_number(11);
-
-        get_and_assert_status(&server, "/v1/chains/ethereum/revelations/0", StatusCode::OK).await;
+        // Add requests - they should be immediately available
+        eth_contract.insert(
+            PROVIDER,
+            0,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        eth_contract.insert(
+            PROVIDER,
+            1,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
+        avax_contract.insert(
+            PROVIDER,
+            100,
+            callback_gas_limit,
+            empty_price_ids.clone(),
+            publish_time,
+        );
 
+        // All inserted requests should be immediately available
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/1",
-            StatusCode::FORBIDDEN,
+            "/v1/chains/ethereum/price-updates/0",
+            StatusCode::OK,
         )
         .await;
-
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/100",
-            StatusCode::FORBIDDEN,
+            "/v1/chains/ethereum/price-updates/1",
+            StatusCode::OK,
         )
         .await;
-
-        eth_contract.set_block_number(12);
-        avax_contract.set_block_number(12);
-
-        get_and_assert_status(&server, "/v1/chains/ethereum/revelations/1", StatusCode::OK).await;
-
         get_and_assert_status(
             &server,
-            "/v1/chains/ethereum/revelations/2",
-            StatusCode::FORBIDDEN,
+            "/v1/chains/avalanche/price-updates/100",
+            StatusCode::OK,
         )
         .await;
 
+        // Non-inserted requests should still be forbidden
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/100",
-            StatusCode::OK,
+            "/v1/chains/ethereum/price-updates/2",
+            StatusCode::FORBIDDEN,
         )
         .await;
-
         get_and_assert_status(
             &server,
-            "/v1/chains/avalanche/revelations/101",
+            "/v1/chains/avalanche/price-updates/101",
             StatusCode::FORBIDDEN,
         )
         .await;

+ 38 - 50
apps/argus/src/api/price_updates.rs

@@ -5,7 +5,6 @@ use {
         extract::{Path, Query, State},
         Json,
     },
-    serde_with::serde_as,
     tokio::try_join,
     utoipa::{IntoParams, ToSchema},
 };
@@ -26,11 +25,13 @@ responses(
 ),
 params(PriceUpdatePathParams, PriceUpdateQueryParams)
 )]
-pub async fn price_updates(
+pub async fn price_update(
     State(state): State<crate::api::ApiState>,
     Path(PriceUpdatePathParams { chain_id, sequence }): Path<PriceUpdatePathParams>,
     Query(PriceUpdateQueryParams { format }): Query<PriceUpdateQueryParams>,
 ) -> Result<Json<GetPriceUpdateResponse>, RestError> {
+    let _ = format; // Ignore the unused variable
+
     state
         .metrics
         .http_requests
@@ -50,53 +51,45 @@ pub async fn price_updates(
         .contract
         .get_block_number(state.confirmed_block_status);
 
-    let (maybe_request, current_block_number) =
+    let (maybe_request, _current_block_number) =
         try_join!(maybe_request_fut, current_block_number_fut).map_err(|e| {
             tracing::error!(chain_id = chain_id, "RPC request failed {}", e);
             RestError::TemporarilyUnavailable
         })?;
 
     match maybe_request {
-        Some(r)
-            if current_block_number.saturating_sub(state.update_delay_blocks) >= r.block_number =>
-        {
-            // Get the price update data for the requested price IDs
-            let update_data = state.state.get_price_update_data(&r.price_ids).map_err(|e| {
-                tracing::error!(
-                    chain_id = chain_id,
-                    sequence = sequence,
-                    "Price update data retrieval failed {}",
-                    e
-                );
-                RestError::Unknown
-            })?;
-
-            // Format the response based on the requested format
-            let response_format = format.unwrap_or(ResponseFormat::Json);
+        Some(request) => {
+            // In a real implementation, we would fetch the price update data from a data source
+            // For now, we'll just return a mock response
+            let price_update_data =
+                generate_price_update_data(&request.price_ids, request.publish_time.as_u64());
 
             Ok(Json(GetPriceUpdateResponse {
-                sequence_number: sequence,
-                price_ids: r.price_ids.iter().map(|id| format!("0x{}", hex::encode(id))).collect(),
-                update_data: match response_format {
-                    ResponseFormat::Json => PriceUpdateData::Json {
-                        data: update_data.iter().map(|data| {
-                            serde_json::to_value(data).unwrap_or_default()
-                        }).collect()
-                    },
-                    ResponseFormat::Binary => PriceUpdateData::Binary {
-                        data: update_data.iter().map(|data| {
-                            data.clone()
-                        }).collect()
-                    },
-                },
-                publish_time: r.publish_time.as_u64(),
+                data: PriceUpdateData::new(price_update_data),
             }))
         }
-        Some(_) => Err(RestError::PendingConfirmation),
         None => Err(RestError::NoPendingRequest),
     }
 }
 
+// Helper function to generate price update data based on price IDs and publish time
+// In a real implementation, this would fetch actual price data from a data source
+fn generate_price_update_data(price_ids: &[[u8; 32]], publish_time: u64) -> Vec<u8> {
+    // This is just a placeholder implementation
+    // In a real system, we would generate actual price update data
+    let mut data = Vec::new();
+
+    // Add publish time to the data
+    data.extend_from_slice(&publish_time.to_be_bytes());
+
+    // Add a simple representation of each price ID
+    for price_id in price_ids {
+        data.extend_from_slice(price_id);
+    }
+
+    data
+}
+
 #[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
 #[into_params(parameter_in=Path)]
 pub struct PriceUpdatePathParams {
@@ -120,23 +113,18 @@ pub enum ResponseFormat {
     Binary,
 }
 
-#[derive(Debug, serde::Serialize, serde::Deserialize, ToSchema)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, ToSchema, PartialEq)]
 pub struct GetPriceUpdateResponse {
-    pub sequence_number: u64,
-    pub price_ids: Vec<String>,
-    pub update_data: PriceUpdateData,
-    pub publish_time: u64,
+    pub data: PriceUpdateData,
 }
 
-#[serde_as]
 #[derive(Debug, serde::Serialize, serde::Deserialize, ToSchema, PartialEq)]
-#[serde(tag = "format", rename_all = "kebab-case")]
-pub enum PriceUpdateData {
-    Json {
-        data: Vec<serde_json::Value>,
-    },
-    Binary {
-        #[serde_as(as = "Vec<serde_with::base64::Base64>")]
-        data: Vec<Vec<u8>>,
-    },
+pub struct PriceUpdateData {
+    data: Vec<u8>,
+}
+
+impl PriceUpdateData {
+    pub fn new(data: Vec<u8>) -> Self {
+        Self { data }
+    }
 }

+ 25 - 0
apps/argus/src/chain/ethereum.rs

@@ -271,3 +271,28 @@ impl<T: JsonRpcClient + 'static> PulseReader for Pulse<Provider<T>> {
         result.map_err(|e| e.into())
     }
 }
+
+impl<T: JsonRpcClient + 'static> Pulse<Provider<T>> {
+    /// Get the current sequence number from the contract.
+    ///
+    /// This method directly accesses the contract's storage to get the currentSequenceNumber.
+    pub async fn get_current_sequence_number(&self) -> Result<u64> {
+        // The currentSequenceNumber is stored in the State struct at slot 0, offset 32 bytes
+        // (after admin, pythFeeInWei, accruedFeesInWei, and pyth)
+        let storage_slot = ethers::types::H256::zero();
+        let storage_value = self.client().get_storage_at(
+            self.address(),
+            storage_slot,
+            None,
+        ).await?;
+
+        // H256 is always 32 bytes, so we don't need to check the length
+
+        // The currentSequenceNumber is stored at offset 32 bytes in the storage slot
+        // Extract the last 8 bytes (u64) from the 32-byte value
+        let mut u64_bytes = [0u8; 8];
+        u64_bytes.copy_from_slice(&storage_value.as_bytes()[24..32]);
+
+        Ok(u64::from_be_bytes(u64_bytes))
+    }
+}

+ 10 - 4
apps/argus/src/chain/reader.rs

@@ -51,6 +51,15 @@ pub trait PulseReader: Send + Sync {
         to_block: BlockNumber,
     ) -> Result<Vec<RequestedWithCallbackEvent>>;
 
+    /// Alias for get_price_update_requested_events to maintain compatibility with existing code
+    async fn get_request_with_callback_events(
+        &self,
+        from_block: BlockNumber,
+        to_block: BlockNumber,
+    ) -> Result<Vec<RequestedWithCallbackEvent>> {
+        self.get_price_update_requested_events(from_block, to_block).await
+    }
+
     /// Estimate the gas required to execute a callback for price updates.
     async fn estimate_execute_callback_gas(
         &self,
@@ -104,10 +113,9 @@ pub mod mock {
                 requests: RwLock::new(
                     requests
                         .iter()
-                        .map(|&(a, s, b, c, ref p, t)| Request {
+                        .map(|&(a, s, _, c, ref p, t)| Request {
                             requester: a,
                             sequence_number: s,
-                            block_number: b,
                             callback_gas_limit: c,
                             price_ids: p.clone(),
                             publish_time: t,
@@ -122,7 +130,6 @@ pub mod mock {
             &self,
             requester: Address,
             sequence: u64,
-            block_number: BlockNumber,
             callback_gas_limit: U256,
             price_ids: Vec<[u8; 32]>,
             publish_time: U256,
@@ -130,7 +137,6 @@ pub mod mock {
             self.requests.write().unwrap().push(Request {
                 requester,
                 sequence_number: sequence,
-                block_number,
                 callback_gas_limit,
                 price_ids,
                 publish_time,

+ 54 - 37
apps/argus/src/command/generate.rs

@@ -1,15 +1,14 @@
 use {
     crate::{
-        api::GetRandomValueResponse,
-        chain::ethereum::SignablePythContract,
+        chain::ethereum::{PulseEvents, SignablePythContract},
         config::{Config, GenerateOptions},
     },
-    anyhow::Result,
-    base64::{engine::general_purpose::STANDARD as base64_standard_engine, Engine as _},
+    anyhow::{anyhow, Result},
+    ethers::{contract::EthLogDecode, types::Bytes},
     std::sync::Arc,
 };
 
-/// Run the entire random number generation protocol to produce a random number.
+/// Request a price update from the Pulse contract and execute the callback.
 pub async fn generate(opts: &GenerateOptions) -> Result<()> {
     let contract = Arc::new(
         SignablePythContract::from_config(
@@ -19,45 +18,63 @@ pub async fn generate(opts: &GenerateOptions) -> Result<()> {
         .await?,
     );
 
-    let user_randomness = rand::random::<[u8; 32]>();
-    let provider = opts.provider;
+    // Define the price IDs we want to update
+    // In a real implementation, these would come from configuration or command line arguments
+    let price_ids: Vec<[u8; 32]> = vec![];
+    if price_ids.is_empty() {
+        return Err(anyhow!("No price IDs specified for update"));
+    }
+
+    // Request a price update on the contract
+    // The publish_time would typically be the current time or a specific time in the future
+    let publish_time = chrono::Utc::now().timestamp() as u64;
+    let callback_gas_limit = 500000; // Example gas limit for the callback
 
-    // Request a random number on the contract
     let sequence_number = contract
-        .request_wrapper(&provider, &user_randomness, opts.blockhash)
-        .await?;
+        .request_price_updates_with_callback(
+            publish_time.into(),
+            price_ids.clone(),
+            callback_gas_limit.into(),
+        )
+        .send()
+        .await?
+        .await?
+        .ok_or_else(|| anyhow!("Failed to get transaction receipt"))?
+        .logs
+        .iter()
+        .find_map(|log| {
+            let raw_log = ethers::abi::RawLog::from(log.clone());
+            if let Ok(PulseEvents::PriceUpdateRequestedFilter(event_data)) =
+                PulseEvents::decode_log(&raw_log)
+            {
+                Some(event_data.request.sequence_number)
+            } else {
+                None
+            }
+        })
+        .ok_or_else(|| anyhow!("Failed to find sequence number in transaction logs"))?;
 
-    tracing::info!(sequence_number = sequence_number, "random number requested",);
+    tracing::info!(sequence_number = sequence_number, "Price update requested");
 
-    // Get the committed value from the provider
-    let resp = reqwest::get(opts.url.join(&format!(
-        "/v1/chains/{}/revelations/{}",
-        opts.chain_id, sequence_number
-    ))?)
-    .await?
-    .json::<GetRandomValueResponse>()
-    .await?;
+    // In a real implementation, we would fetch price data from a source
+    // For this example, we'll use empty update data
+    let update_data: Vec<Bytes> = vec![];
 
-    tracing::info!(
-        response = base64_standard_engine.encode(resp.value.data()),
-        "Retrieved the provider's random value.",
-    );
-    let provider_randomness = resp.value.data();
-
-    // Submit the provider's and our values to the contract to reveal the random number.
-    let random_value = contract
-        .reveal_wrapper(
-            &provider,
-            sequence_number,
-            &user_randomness,
-            provider_randomness,
-        )
+    // Execute the callback with the price data
+    let result = contract
+        .execute_callback(sequence_number, update_data, price_ids)
+        .send()
+        .await?
         .await?;
 
-    tracing::info!(
-        number = base64_standard_engine.encode(random_value),
-        "Random number generated."
-    );
+    if let Some(receipt) = result {
+        tracing::info!(
+            transaction_hash = ?receipt.transaction_hash,
+            "Price update callback executed successfully"
+        );
+    } else {
+        tracing::error!("Price update callback failed: no receipt returned");
+    }
 
     Ok(())
 }

+ 1 - 1
apps/argus/src/command/get_request.rs

@@ -15,7 +15,7 @@ pub async fn get_request(opts: &GetRequestOptions) -> Result<()> {
     )?);
 
     let r = contract
-        .get_request(opts.provider, opts.sequence)
+        .get_request(opts.sequence)
         .call()
         .await?;
     tracing::info!("Found request: {:?}", r);

+ 40 - 24
apps/argus/src/command/inspect.rs

@@ -9,6 +9,7 @@ use {
         middleware::Middleware,
         prelude::{Http, Provider},
     },
+    std::time::{Duration, SystemTime},
 };
 
 pub async fn inspect(opts: &InspectOptions) -> Result<()> {
@@ -42,11 +43,23 @@ async fn inspect_chain(
         > 0;
 
     let contract = PythContract::from_config(chain_config)?;
-    let entropy_provider = contract.get_default_provider().call().await?;
-    let provider_info = contract.get_provider_info(entropy_provider).call().await?;
-    let mut current_request_number = provider_info.sequence_number;
-    println!("Initial request number: {}", current_request_number);
+
+    // Get the current sequence number directly from the contract's storage
+    let current_sequence_number = contract.get_current_sequence_number().await?;
+
+    // The current sequence number is the next one to be assigned, so subtract 1 to get the latest
+    let latest_sequence_number = current_sequence_number.saturating_sub(1);
+    let mut current_request_number = latest_sequence_number;
+
+    println!("Latest sequence number: {}", current_request_number);
+
+    if current_request_number == 0 {
+        println!("No requests found");
+        return Ok(());
+    }
+
     let last_request_number = current_request_number.saturating_sub(num_requests);
+
     if multicall_exists {
         println!("Using multicall");
         let mut multicall = Multicall::new(
@@ -60,26 +73,20 @@ async fn inspect_chain(
                 if current_request_number == 0 {
                     break;
                 }
-                multicall.add_call(
-                    contract.get_request(entropy_provider, current_request_number),
-                    false,
-                );
+                multicall.add_call(contract.get_request(current_request_number), false);
                 current_request_number -= 1;
             }
             let return_data: Vec<Request> = multicall.call_array().await?;
             for request in return_data {
-                process_request(rpc_provider.clone(), request).await?;
+                process_request(request).await?;
             }
             println!("Current request number: {}", current_request_number);
         }
     } else {
         println!("Multicall not deployed in this chain, fetching requests one by one");
         while current_request_number > last_request_number {
-            let request = contract
-                .get_request(entropy_provider, current_request_number)
-                .call()
-                .await?;
-            process_request(rpc_provider.clone(), request).await?;
+            let request = contract.get_request(current_request_number).call().await?;
+            process_request(request).await?;
             current_request_number -= 1;
             if current_request_number % 100 == 0 {
                 println!("Current request number: {}", current_request_number);
@@ -89,17 +96,26 @@ async fn inspect_chain(
     Ok(())
 }
 
-async fn process_request(rpc_provider: Provider<Http>, request: Request) -> Result<()> {
-    if request.sequence_number != 0 && request.is_request_with_callback {
-        let block = rpc_provider
-            .get_block(request.block_number)
-            .await?
-            .expect("Block not found");
-        let datetime = chrono::DateTime::from_timestamp(block.timestamp.as_u64() as i64, 0)
-            .expect("Invalid timestamp");
+async fn process_request(request: Request) -> Result<()> {
+    if request.sequence_number != 0 {
+        // Convert publish_time to a datetime
+        let publish_time = request.publish_time.as_u64();
+        let datetime = if publish_time > 0 {
+            match SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(publish_time)) {
+                Some(time) => format!("{:?}", time),
+                None => "Invalid time".to_string(),
+            }
+        } else {
+            "N/A".to_string()
+        };
+
         println!(
-            "{} sequence_number:{} block_number:{} requester:{}",
-            datetime, request.sequence_number, request.block_number, request.requester
+            "{} sequence_number:{} publish_time:{} requester:{} price_ids:{}",
+            datetime,
+            request.sequence_number,
+            request.publish_time,
+            request.requester,
+            request.price_ids.len()
         );
     }
     Ok(())

+ 21 - 61
apps/argus/src/command/register_provider.rs

@@ -1,39 +1,25 @@
 use {
     crate::{
-        api::{get_register_uri, ChainId},
         chain::ethereum::SignablePythContract,
         config::{Config, EthereumConfig, ProviderConfig, RegisterProviderOptions},
-        state::PebbleHashChain,
     },
     anyhow::{anyhow, Result},
-    ethers::{
-        abi::Bytes,
-        signers::{LocalWallet, Signer},
-        types::U256,
-    },
+    ethers::signers::{LocalWallet, Signer},
     std::sync::Arc,
 };
 
-#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
-pub struct CommitmentMetadata {
-    pub seed: [u8; 32],
-    pub chain_length: u64,
-}
-
-/// Register as a randomness provider. This method will generate and commit to a new random
-/// hash chain from the configured secret & a newly generated random value.
+/// Register as a price update provider. This method will register the provider with the Pulse contract.
 pub async fn register_provider(opts: &RegisterProviderOptions) -> Result<()> {
     let config = Config::load(&opts.config.config)?;
     let chain_config = config.get_chain_config(&opts.chain_id)?;
 
-    register_provider_from_config(&config.provider, &opts.chain_id, &chain_config).await?;
+    register_provider_from_config(&config.provider, &chain_config).await?;
 
     Ok(())
 }
 
 pub async fn register_provider_from_config(
     provider_config: &ProviderConfig,
-    chain_id: &ChainId,
     chain_config: &EthereumConfig,
 ) -> Result<()> {
     let private_key_string = provider_config.private_key.load()?.ok_or(anyhow!(
@@ -43,51 +29,25 @@ pub async fn register_provider_from_config(
     // Initialize a Provider to interface with the EVM contract.
     let contract =
         Arc::new(SignablePythContract::from_config(chain_config, &private_key_string).await?);
-    // Create a new random hash chain.
-    let random = rand::random::<[u8; 32]>();
-    let secret = provider_config
-        .secret
-        .load()?
-        .ok_or(anyhow!("Please specify a provider secret in the config"))?;
-
-    let commitment_length = provider_config.chain_length;
-    tracing::info!("Generating hash chain");
-    let chain = PebbleHashChain::from_config(
-        &secret,
-        chain_id,
-        &private_key_string.parse::<LocalWallet>()?.address(),
-        &chain_config.contract_addr,
-        &random,
-        commitment_length,
-        provider_config.chain_sample_interval,
-    )?;
-    tracing::info!("Done generating hash chain");
 
-    // Arguments to the contract to register our new provider.
-    let fee_in_wei = chain_config.fee;
-    let commitment = chain.reveal_ith(0)?;
-    // Store the random seed and chain length in the metadata field so that we can regenerate the hash
-    // chain at-will. (This is secure because you can't generate the chain unless you also have the secret)
-    let commitment_metadata = CommitmentMetadata {
-        seed: random,
-        chain_length: commitment_length,
-    };
-    let uri = get_register_uri(&provider_config.uri, chain_id)?;
-    let call = contract.register(
-        fee_in_wei,
-        commitment,
-        bincode::serialize(&commitment_metadata)?.into(),
-        commitment_length,
-        // Use Bytes to serialize the uri. Most users will be using JS/TS to deserialize this uri.
-        // Bincode is a different encoding mechanisms, and I didn't find any JS/TS library to parse bincode.
-        Bytes::from(uri.as_str()).into(),
-    );
-    let mut gas_estimate = call.estimate_gas().await?;
-    let gas_multiplier = U256::from(2); //TODO: smarter gas estimation
-    gas_estimate *= gas_multiplier;
-    let call_with_gas = call.gas(gas_estimate);
-    if let Some(r) = call_with_gas.send().await?.await? {
-        tracing::info!("Registered provider: {:?}", r);
+    let wallet = private_key_string.parse::<LocalWallet>()?;
+    let provider_address = wallet.address();
+
+    // Register the provider with the contract
+    tracing::info!("Registering provider with address: {:?}", provider_address);
+    tracing::info!("Provider fee: {}", chain_config.fee);
+
+    // Register the provider with the fee
+    if let Some(receipt) = contract
+        .register_provider(chain_config.fee)
+        .send()
+        .await?
+        .await?
+    {
+        tracing::info!("Provider registration successful: {:?}", receipt);
+    } else {
+        tracing::error!("Provider registration failed: no receipt returned");
+        return Err(anyhow!("Provider registration failed: no receipt returned"));
     }
 
     Ok(())

+ 16 - 4
apps/argus/src/command/request_randomness.rs

@@ -4,7 +4,8 @@ use {
         config::{Config, RequestRandomnessOptions},
     },
     anyhow::Result,
-    std::sync::Arc,
+    ethers::types::U256,
+    std::{sync::Arc, time::{SystemTime, UNIX_EPOCH}},
 };
 
 pub async fn request_randomness(opts: &RequestRandomnessOptions) -> Result<()> {
@@ -16,12 +17,23 @@ pub async fn request_randomness(opts: &RequestRandomnessOptions) -> Result<()> {
         .await?,
     );
 
-    let user_randomness = rand::random::<[u8; 32]>();
+    // For Pulse, we need to request price updates instead of random numbers
+    // Define some example price IDs to update (these should be replaced with actual price IDs in production)
+    let price_ids = vec![[0u8; 32]; 1]; // Example with one price ID
+
+    // Use current timestamp as publish time
+    let current_time = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
+    let publish_time = U256::from(current_time);
+
+    // Set a reasonable callback gas limit
+    let callback_gas_limit = U256::from(500000); // 500k gas
+
+    // Request price updates with callback
     let sequence_number = contract
-        .request_wrapper(&opts.provider, &user_randomness, false)
+        .request_price_updates_wrapper(publish_time, price_ids, callback_gas_limit)
         .await?;
 
-    tracing::info!("sequence number: {:#?}", sequence_number);
+    tracing::info!("Price update requested with sequence number: {:#?}", sequence_number);
 
     Ok(())
 }

+ 14 - 84
apps/argus/src/command/run.rs

@@ -2,18 +2,16 @@ use {
     crate::{
         api::{self, BlockchainState, ChainId},
         chain::ethereum::InstrumentedPythContract,
-        command::register_provider::CommitmentMetadata,
-        config::{Commitment, Config, EthereumConfig, RunOptions},
+        config::{Config, EthereumConfig, RunOptions},
         keeper::{self, keeper_metrics::KeeperMetrics},
-        state::{HashChainState, PebbleHashChain},
     },
-    fortuna::eth_utils::traced_client::{RpcMetrics, TracedClient},
     anyhow::{anyhow, Error, Result},
     axum::Router,
     ethers::{
         middleware::Middleware,
         types::{Address, BlockNumber},
     },
+    fortuna::eth_utils::traced_client::{RpcMetrics, TracedClient},
     futures::future::join_all,
     prometheus_client::{
         encoding::EncodeLabelSet,
@@ -48,18 +46,18 @@ pub async fn run_api(
     #[derive(OpenApi)]
     #[openapi(
     paths(
-    crate::api::revelation,
+    crate::api::price_update,
     crate::api::chain_ids,
     ),
     components(
     schemas(
-    crate::api::GetRandomValueResponse,
-    crate::api::Blob,
-    crate::api::BinaryEncoding,
+    crate::api::GetPriceUpdateResponse,
+    crate::api::PriceUpdateData,
+    crate::api::ResponseFormat,
     )
     ),
     tags(
-    (name = "fortuna", description = "Random number service for the Pyth Entropy protocol")
+    (name = "argus", description = "Price update service for the Pyth Pulse protocol")
     )
     )]
     struct ApiDoc;
@@ -129,22 +127,16 @@ pub async fn run_keeper(
 
 pub async fn run(opts: &RunOptions) -> Result<()> {
     let config = Config::load(&opts.config.config)?;
-    let secret = config.provider.secret.load()?.ok_or(anyhow!(
-        "Please specify a provider secret in the config file."
-    ))?;
     let (tx_exit, rx_exit) = watch::channel(false);
     let metrics_registry = Arc::new(RwLock::new(Registry::default()));
     let rpc_metrics = Arc::new(RpcMetrics::new(metrics_registry.clone()).await);
 
     let mut tasks = Vec::new();
     for (chain_id, chain_config) in config.chains.clone() {
-        let secret_copy = secret.clone();
         let rpc_metrics = rpc_metrics.clone();
         tasks.push(spawn(async move {
             let state = setup_chain_state(
                 &config.provider.address,
-                &secret_copy,
-                config.provider.chain_sample_interval,
                 &chain_id,
                 &chain_config,
                 rpc_metrics,
@@ -211,8 +203,6 @@ pub async fn run(opts: &RunOptions) -> Result<()> {
 
 async fn setup_chain_state(
     provider: &Address,
-    secret: &str,
-    chain_sample_interval: u64,
     chain_id: &ChainId,
     chain_config: &EthereumConfig,
     rpc_metrics: Arc<RpcMetrics>,
@@ -222,83 +212,23 @@ async fn setup_chain_state(
         chain_id.clone(),
         rpc_metrics,
     )?);
-    let mut provider_commitments = chain_config.commitments.clone().unwrap_or_default();
-    provider_commitments.sort_by(|c1, c2| {
-        c1.original_commitment_sequence_number
-            .cmp(&c2.original_commitment_sequence_number)
-    });
 
+    // Verify the provider is registered
     let provider_info = contract.get_provider_info(*provider).call().await?;
-    let latest_metadata = bincode::deserialize::<CommitmentMetadata>(
-        &provider_info.commitment_metadata,
-    )
-    .map_err(|e| {
-        anyhow!(
-            "Chain: {} - Failed to deserialize commitment metadata: {}",
-            &chain_id,
-            e
-        )
-    })?;
-
-    let last_prior_commitment = provider_commitments.last();
-    if last_prior_commitment.is_some()
-        && last_prior_commitment
-            .unwrap()
-            .original_commitment_sequence_number
-            >= provider_info.original_commitment_sequence_number
-    {
-        return Err(anyhow!("The current hash chain for chain id {} has configured commitments for sequence numbers greater than the current on-chain sequence number. Are the commitments configured correctly?", &chain_id));
-    }
-
-    provider_commitments.push(Commitment {
-        seed: latest_metadata.seed,
-        chain_length: latest_metadata.chain_length,
-        original_commitment_sequence_number: provider_info.original_commitment_sequence_number,
-    });
-
-    // TODO: we may want to load the hash chain in a lazy/fault-tolerant way. If there are many blockchains,
-    // then it's more likely that some RPC fails. We should tolerate these faults and generate the hash chain
-    // later when a user request comes in for that chain.
-
-    let mut offsets = Vec::<usize>::new();
-    let mut hash_chains = Vec::<PebbleHashChain>::new();
-
-    for commitment in &provider_commitments {
-        let offset = commitment.original_commitment_sequence_number.try_into()?;
-        offsets.push(offset);
-
-        let pebble_hash_chain = PebbleHashChain::from_config(
-            secret,
-            chain_id,
+    if !provider_info.is_registered {
+        return Err(anyhow!(
+            "Provider {} is not registered on chain {}",
             provider,
-            &chain_config.contract_addr,
-            &commitment.seed,
-            commitment.chain_length,
-            chain_sample_interval,
-        )
-        .map_err(|e| anyhow!("Failed to create hash chain: {}", e))?;
-        hash_chains.push(pebble_hash_chain);
+            chain_id
+        ));
     }
 
-    let chain_state = HashChainState {
-        offsets,
-        hash_chains,
-    };
-
-    if chain_state.reveal(provider_info.original_commitment_sequence_number)?
-        != provider_info.original_commitment
-    {
-        return Err(anyhow!("The root of the generated hash chain for chain id {} does not match the commitment. Are the secret and chain length configured correctly?", &chain_id));
-    } else {
-        tracing::info!("Root of chain id {} matches commitment", &chain_id);
-    }
+    tracing::info!("Provider {} is registered on chain {}", provider, chain_id);
 
     let state = BlockchainState {
         id: chain_id.clone(),
-        state: Arc::new(chain_state),
         contract,
         provider_address: *provider,
-        reveal_delay_blocks: chain_config.reveal_delay_blocks,
         confirmed_block_status: chain_config.confirmed_block_status,
     };
     Ok(state)

+ 10 - 123
apps/argus/src/command/setup_provider.rs

@@ -1,16 +1,14 @@
 use {
     crate::{
-        api::{get_register_uri, ChainId},
+        api::ChainId,
         chain::ethereum::{ProviderInfo, SignablePythContract},
-        command::register_provider::{register_provider_from_config, CommitmentMetadata},
+        command::register_provider::register_provider_from_config,
         config::{Config, EthereumConfig, SetupProviderOptions},
-        state::{HashChainState, PebbleHashChain},
     },
     anyhow::{anyhow, Result},
     ethers::{
-        abi::Bytes as AbiBytes,
         signers::{LocalWallet, Signer},
-        types::{Address, Bytes},
+        types::Address,
     },
     futures::future::join_all,
     std::sync::Arc,
@@ -56,10 +54,8 @@ pub async fn setup_provider(opts: &SetupProviderOptions) -> Result<()> {
 
 /// Setup provider for a single chain.
 /// 1. Register if there was no previous registration.
-/// 2. Re-register if there are no more random numbers to request on the contract.
-/// 3. Re-register if there is a mismatch in generated hash chain.
-/// 4. Update provider fee if there is a mismatch with the fee set on contract.
-/// 5. Update provider uri if there is a mismatch with the uri set on contract.
+/// 2. Update provider fee if there is a mismatch with the fee set on contract.
+/// 3. Update fee manager if there is a mismatch with the fee manager set on contract.
 #[tracing::instrument(name = "setup_chain_provider", skip_all, fields(chain_id = chain_id))]
 async fn setup_chain_provider(
     config: &Config,
@@ -79,84 +75,22 @@ async fn setup_chain_provider(
     let provider_info = contract.get_provider_info(provider_address).call().await?;
     tracing::info!("Provider info: {:?}", provider_info);
 
-    let mut register = false;
-
-    // This condition satisfies for both when there is no registration and when there are no
-    // more random numbers left to request
-    if provider_info.end_sequence_number <= provider_info.sequence_number {
-        tracing::info!(
-            "endSequenceNumber <= sequenceNumber. endSequenceNumber={}, sequenceNumber={}",
-            provider_info.end_sequence_number,
-            provider_info.sequence_number
-        );
-        register = true;
-    } else {
-        let metadata =
-            bincode::deserialize::<CommitmentMetadata>(&provider_info.commitment_metadata)
-                .map_err(|e| {
-                    anyhow!(
-                        "Chain: {} - Failed to deserialize commitment metadata: {}",
-                        &chain_id,
-                        e
-                    )
-                })?;
-
-        let secret = provider_config.secret.load()?.ok_or(anyhow!(
-            "Please specify a provider secret in the config file."
-        ))?;
-        if metadata.chain_length != provider_config.chain_length {
-            tracing::info!(
-                "Chain length mismatch. metadata.chain_length={}, provider_config.chain_length={}",
-                metadata.chain_length,
-                provider_config.chain_length
-            );
-            register = true;
-        } else {
-            let hash_chain = PebbleHashChain::from_config(
-                &secret,
-                chain_id,
-                &provider_address,
-                &chain_config.contract_addr,
-                &metadata.seed,
-                provider_config.chain_length,
-                provider_config.chain_sample_interval,
-            )?;
-            let chain_state = HashChainState {
-                offsets: vec![provider_info
-                    .original_commitment_sequence_number
-                    .try_into()?],
-                hash_chains: vec![hash_chain],
-            };
-
-            if chain_state.reveal(provider_info.original_commitment_sequence_number)?
-                != provider_info.original_commitment
-            {
-                tracing::info!(
-                    "The root of the generated hash chain does not match the commitment",
-                );
-                register = true;
-            }
-        }
-    }
-    if register {
-        tracing::info!("Registering");
-        register_provider_from_config(provider_config, chain_id, chain_config)
+    // Register if the provider is not already registered
+    if !provider_info.is_registered {
+        tracing::info!("Provider not registered, registering now");
+        register_provider_from_config(provider_config, chain_config)
             .await
             .map_err(|e| anyhow!("Chain: {} - Failed to register provider: {}", &chain_id, e))?;
         tracing::info!("Registered");
     }
 
+    // Fetch updated provider info after registration
     let provider_info = contract.get_provider_info(provider_address).call().await?;
 
     sync_fee(&contract, &provider_info, chain_config.fee)
         .in_current_span()
         .await?;
 
-    let uri = get_register_uri(&provider_config.uri, chain_id)?;
-    sync_uri(&contract, &provider_info, uri)
-        .in_current_span()
-        .await?;
-
     sync_fee_manager(
         &contract,
         &provider_info,
@@ -165,34 +99,6 @@ async fn setup_chain_provider(
     .in_current_span()
     .await?;
 
-    sync_max_num_hashes(
-        &contract,
-        &provider_info,
-        chain_config.max_num_hashes.unwrap_or(0),
-    )
-    .in_current_span()
-    .await?;
-
-    Ok(())
-}
-
-async fn sync_uri(
-    contract: &Arc<SignablePythContract>,
-    provider_info: &ProviderInfo,
-    uri: String,
-) -> Result<()> {
-    let uri_as_bytes: Bytes = AbiBytes::from(uri.as_str()).into();
-    if provider_info.uri != uri_as_bytes {
-        tracing::info!("Updating provider uri to {}", uri);
-        if let Some(receipt) = contract
-            .set_provider_uri(uri_as_bytes)
-            .send()
-            .await?
-            .await?
-        {
-            tracing::info!("Updated provider uri: {:?}", receipt);
-        }
-    }
     Ok(())
 }
 
@@ -228,22 +134,3 @@ async fn sync_fee_manager(
     }
     Ok(())
 }
-
-async fn sync_max_num_hashes(
-    contract: &Arc<SignablePythContract>,
-    provider_info: &ProviderInfo,
-    max_num_hashes: u32,
-) -> Result<()> {
-    if provider_info.max_num_hashes != max_num_hashes {
-        tracing::info!("Updating provider max num hashes to {:?}", max_num_hashes);
-        if let Some(receipt) = contract
-            .set_max_num_hashes(max_num_hashes)
-            .send()
-            .await?
-            .await?
-        {
-            tracing::info!("Updated provider max num hashes to : {:?}", receipt);
-        }
-    }
-    Ok(())
-}

+ 0 - 4
apps/argus/src/keeper.rs

@@ -7,7 +7,6 @@ use {
             get_latest_safe_block, process_backlog, process_new_blocks, watch_blocks_wrapper,
             BlockRange,
         },
-        keeper::commitment::update_commitments_loop,
         keeper::fee::adjust_fee_wrapper,
         keeper::fee::withdraw_fees_wrapper,
         keeper::track::track_balance,
@@ -26,7 +25,6 @@ use {
 };
 
 pub(crate) mod block;
-pub(crate) mod commitment;
 pub(crate) mod fee;
 pub(crate) mod keeper_metrics;
 pub(crate) mod process_event;
@@ -164,8 +162,6 @@ pub async fn run_keeper_threads(
         .in_current_span(),
     );
 
-    spawn(update_commitments_loop(contract.clone(), chain_state.clone()).in_current_span());
-
     // Spawn a thread to track the provider info and the balance of the keeper
     spawn(
         async move {

+ 2 - 5
apps/argus/src/keeper/block.rs

@@ -45,11 +45,8 @@ pub async fn get_latest_safe_block(chain_state: &BlockchainState) -> BlockNumber
             .await
         {
             Ok(latest_confirmed_block) => {
-                tracing::info!(
-                    "Fetched latest safe block {}",
-                    latest_confirmed_block - chain_state.reveal_delay_blocks
-                );
-                return latest_confirmed_block - chain_state.reveal_delay_blocks;
+                tracing::info!("Fetched latest safe block {}", latest_confirmed_block);
+                return latest_confirmed_block;
             }
             Err(e) => {
                 tracing::error!("Error while getting block number. error: {:?}", e);

+ 0 - 64
apps/argus/src/keeper/commitment.rs

@@ -1,64 +0,0 @@
-use {
-    crate::{
-        api::BlockchainState, chain::ethereum::InstrumentedSignablePythContract,
-        keeper::block::get_latest_safe_block,
-    },
-    anyhow::{anyhow, Result},
-    fortuna::eth_utils::utils::send_and_confirm,
-    std::sync::Arc,
-    tokio::time::{self, Duration},
-    tracing::{self, Instrument},
-};
-
-/// Check whether we need to manually update the commitments to reduce numHashes for future
-/// requests and reduce the gas cost of the reveal.
-const UPDATE_COMMITMENTS_INTERVAL: Duration = Duration::from_secs(30);
-const UPDATE_COMMITMENTS_THRESHOLD_FACTOR: f64 = 0.95;
-
-#[tracing::instrument(name = "update_commitments", skip_all)]
-pub async fn update_commitments_loop(
-    contract: Arc<InstrumentedSignablePythContract>,
-    chain_state: BlockchainState,
-) {
-    loop {
-        if let Err(e) = update_commitments_if_necessary(contract.clone(), &chain_state)
-            .in_current_span()
-            .await
-        {
-            tracing::error!("Update commitments. error: {:?}", e);
-        }
-        time::sleep(UPDATE_COMMITMENTS_INTERVAL).await;
-    }
-}
-
-pub async fn update_commitments_if_necessary(
-    contract: Arc<InstrumentedSignablePythContract>,
-    chain_state: &BlockchainState,
-) -> Result<()> {
-    //TODO: we can reuse the result from the last call from the watch_blocks thread to reduce RPCs
-    let latest_safe_block = get_latest_safe_block(chain_state).in_current_span().await;
-    let provider_address = chain_state.provider_address;
-    let provider_info = contract
-        .get_provider_info(provider_address)
-        .block(latest_safe_block) // To ensure we are not revealing sooner than we should
-        .call()
-        .await
-        .map_err(|e| anyhow!("Error while getting provider info. error: {:?}", e))?;
-    if provider_info.max_num_hashes == 0 {
-        return Ok(());
-    }
-    let threshold =
-        ((provider_info.max_num_hashes as f64) * UPDATE_COMMITMENTS_THRESHOLD_FACTOR) as u64;
-    if provider_info.sequence_number - provider_info.current_commitment_sequence_number > threshold
-    {
-        let seq_number = provider_info.sequence_number - 1;
-        let provider_revelation = chain_state
-            .state
-            .reveal(seq_number)
-            .map_err(|e| anyhow!("Error revealing: {:?}", e))?;
-        let contract_call =
-            contract.advance_provider_commitment(provider_address, seq_number, provider_revelation);
-        send_and_confirm(contract_call).await?;
-    }
-    Ok(())
-}

+ 28 - 27
apps/argus/src/keeper/fee.rs

@@ -10,7 +10,6 @@ use {
         types::{Address, U256},
     },
     fortuna::eth_utils::utils::{estimate_tx_cost, send_and_confirm},
-
     std::sync::Arc,
     tokio::time::{self, Duration},
     tracing::{self, Instrument},
@@ -88,8 +87,8 @@ pub async fn adjust_fee_wrapper(
 ) {
     // The maximum balance of accrued fees + provider wallet balance. None if we haven't observed a value yet.
     let mut high_water_pnl: Option<U256> = None;
-    // The sequence number where the keeper last updated the on-chain fee. None if we haven't observed it yet.
-    let mut sequence_number_of_last_fee_update: Option<u64> = None;
+    // Track when we last updated the fee
+    let mut last_fee_update_time: Option<u64> = None;
     loop {
         if let Err(e) = adjust_fee_if_necessary(
             contract.clone(),
@@ -102,13 +101,13 @@ pub async fn adjust_fee_wrapper(
             max_profit_pct,
             min_fee_wei,
             &mut high_water_pnl,
-            &mut sequence_number_of_last_fee_update,
+            &mut last_fee_update_time,
             metrics.clone(),
         )
         .in_current_span()
         .await
         {
-            tracing::error!("Withdrawing fees. error: {:?}", e);
+            tracing::error!("Adjusting fees. error: {:?}", e);
         }
         time::sleep(poll_interval).await;
     }
@@ -123,7 +122,7 @@ pub async fn adjust_fee_wrapper(
 ///   factor prevents the on-chain fee from changing with every single gas price fluctuation.
 ///   Profit scalars are specified in percentage units, min_profit = (min_profit_pct + 100) / 100
 /// - either the fee is increasing or the keeper is earning a profit -- i.e., fees only decrease when the keeper is profitable
-/// - at least one random number has been requested since the last fee update
+/// - at least some time has passed since the last fee update
 ///
 /// These conditions are intended to make sure that the keeper is profitable while also minimizing the number of fee
 /// update transactions.
@@ -139,7 +138,7 @@ pub async fn adjust_fee_if_necessary(
     max_profit_pct: u64,
     min_fee_wei: u128,
     high_water_pnl: &mut Option<U256>,
-    sequence_number_of_last_fee_update: &mut Option<u64>,
+    last_fee_update_time: &mut Option<u64>,
     metrics: Arc<KeeperMetrics>,
 ) -> Result<()> {
     let provider_info = contract
@@ -200,17 +199,22 @@ pub async fn adjust_fee_if_necessary(
         None => false,
     };
 
-    // Determine if the chain has seen activity since the last fee update.
-    let is_chain_active: bool = match sequence_number_of_last_fee_update {
-        Some(n) => provider_info.sequence_number > *n,
-        None => {
-            // We don't want to adjust the fees on server start for unused chains, hence false here.
-            false
-        }
+    // Get current timestamp to determine if enough time has passed since last update
+    let current_time = std::time::SystemTime::now()
+        .duration_since(std::time::UNIX_EPOCH)
+        .unwrap_or_default()
+        .as_secs();
+
+    // Determine if enough time has passed since the last fee update
+    // We'll use a 10-minute minimum interval between fee updates
+    const MIN_FEE_UPDATE_INTERVAL: u64 = 600; // 10 minutes
+    let is_update_time = match last_fee_update_time {
+        Some(last_time) => current_time.saturating_sub(*last_time) >= MIN_FEE_UPDATE_INTERVAL,
+        None => true, // First run, allow update
     };
 
     let provider_fee: u128 = provider_info.fee_in_wei;
-    if is_chain_active
+    if is_update_time
         && ((provider_fee > target_fee_max && can_reduce_fees) || provider_fee < target_fee_min)
     {
         tracing::info!(
@@ -218,19 +222,19 @@ pub async fn adjust_fee_if_necessary(
             provider_fee,
             target_fee
         );
-        let contract_call = contract.set_provider_fee_as_fee_manager(provider_address, target_fee);
+        let contract_call = contract.set_provider_fee(target_fee);
         send_and_confirm(contract_call).await?;
 
-        *sequence_number_of_last_fee_update = Some(provider_info.sequence_number);
+        *last_fee_update_time = Some(current_time);
     } else {
         tracing::info!(
-            "Skipping fee adjustment. Current: {:?} Target: {:?} [{:?}, {:?}] Current Sequence Number: {:?} Last updated sequence number {:?} Current pnl: {:?} High water pnl: {:?}",
+            "Skipping fee adjustment. Current: {:?} Target: {:?} [{:?}, {:?}] Last update time: {:?} Current time: {:?} Current pnl: {:?} High water pnl: {:?}",
             provider_fee,
             target_fee,
             target_fee_min,
             target_fee_max,
-            provider_info.sequence_number,
-            sequence_number_of_last_fee_update,
+            last_fee_update_time,
+            current_time,
             current_pnl,
             high_water_pnl
         )
@@ -242,13 +246,10 @@ pub async fn adjust_fee_if_necessary(
         high_water_pnl.unwrap_or(U256::from(0)),
     ));
 
-    // Update sequence number on server start.
-    match sequence_number_of_last_fee_update {
-        Some(_) => (),
-        None => {
-            *sequence_number_of_last_fee_update = Some(provider_info.sequence_number);
-        }
-    };
+    // Initialize last_fee_update_time on first run
+    if last_fee_update_time.is_none() {
+        *last_fee_update_time = Some(current_time);
+    }
 
     Ok(())
 }

+ 13 - 34
apps/argus/src/keeper/keeper_metrics.rs

@@ -17,8 +17,6 @@ pub struct AccountLabel {
 }
 
 pub struct KeeperMetrics {
-    pub current_sequence_number: Family<AccountLabel, Gauge>,
-    pub end_sequence_number: Family<AccountLabel, Gauge>,
     pub balance: Family<AccountLabel, Gauge<f64, AtomicU64>>,
     pub collected_fee: Family<AccountLabel, Gauge<f64, AtomicU64>>,
     pub current_fee: Family<AccountLabel, Gauge<f64, AtomicU64>>,
@@ -30,7 +28,7 @@ pub struct KeeperMetrics {
     pub requests_processed_success: Family<AccountLabel, Counter>,
     pub requests_processed_failure: Family<AccountLabel, Counter>,
     pub requests_reprocessed: Family<AccountLabel, Counter>,
-    pub reveals: Family<AccountLabel, Counter>,
+    pub callbacks_executed: Family<AccountLabel, Counter>,
     pub request_duration_ms: Family<AccountLabel, Histogram>,
     pub retry_count: Family<AccountLabel, Histogram>,
     pub final_gas_multiplier: Family<AccountLabel, Histogram>,
@@ -41,8 +39,6 @@ pub struct KeeperMetrics {
 impl Default for KeeperMetrics {
     fn default() -> Self {
         Self {
-            current_sequence_number: Family::default(),
-            end_sequence_number: Family::default(),
             balance: Family::default(),
             collected_fee: Family::default(),
             current_fee: Family::default(),
@@ -54,7 +50,7 @@ impl Default for KeeperMetrics {
             requests_processed_success: Family::default(),
             requests_processed_failure: Family::default(),
             requests_reprocessed: Family::default(),
-            reveals: Family::default(),
+            callbacks_executed: Family::default(),
             request_duration_ms: Family::new_with_constructor(|| {
                 Histogram::new(
                     vec![
@@ -88,46 +84,35 @@ impl KeeperMetrics {
         let mut writable_registry = registry.write().await;
         let keeper_metrics = KeeperMetrics::default();
 
-        writable_registry.register(
-            "current_sequence_number",
-            "The sequence number for a new request",
-            keeper_metrics.current_sequence_number.clone(),
-        );
-
-        writable_registry.register(
-            "end_sequence_number",
-            "The sequence number for the end request",
-            keeper_metrics.end_sequence_number.clone(),
-        );
 
         writable_registry.register(
             "requests",
-            "Number of requests received through events",
+            "Number of price update requests received through events",
             keeper_metrics.requests.clone(),
         );
 
         writable_registry.register(
             "requests_processed",
-            "Number of requests processed",
+            "Number of price update requests processed",
             keeper_metrics.requests_processed.clone(),
         );
 
         writable_registry.register(
             "requests_processed_success",
-            "Number of requests processed successfully",
+            "Number of price update requests processed successfully",
             keeper_metrics.requests_processed_success.clone(),
         );
 
         writable_registry.register(
             "requests_processed_failure",
-            "Number of requests processed with failure",
+            "Number of price update requests processed with failure",
             keeper_metrics.requests_processed_failure.clone(),
         );
 
         writable_registry.register(
-            "reveal",
-            "Number of reveals",
-            keeper_metrics.reveals.clone(),
+            "callbacks_executed",
+            "Number of price update callbacks executed",
+            keeper_metrics.callbacks_executed.clone(),
         );
 
         writable_registry.register(
@@ -156,19 +141,19 @@ impl KeeperMetrics {
 
         writable_registry.register(
             "total_gas_spent",
-            "Total gas spent revealing requests",
+            "Total gas spent executing callbacks",
             keeper_metrics.total_gas_spent.clone(),
         );
 
         writable_registry.register(
             "total_gas_fee_spent",
-            "Total amount of ETH spent on gas for revealing requests",
+            "Total amount of ETH spent on gas for executing callbacks",
             keeper_metrics.total_gas_fee_spent.clone(),
         );
 
         writable_registry.register(
             "requests_reprocessed",
-            "Number of requests reprocessed",
+            "Number of price update requests reprocessed",
             keeper_metrics.requests_reprocessed.clone(),
         );
 
@@ -211,12 +196,6 @@ impl KeeperMetrics {
                 address: provider_address.to_string(),
             };
 
-            let _ = keeper_metrics
-                .current_sequence_number
-                .get_or_create(&account_label);
-            let _ = keeper_metrics
-                .end_sequence_number
-                .get_or_create(&account_label);
             let _ = keeper_metrics.balance.get_or_create(&account_label);
             let _ = keeper_metrics.collected_fee.get_or_create(&account_label);
             let _ = keeper_metrics.current_fee.get_or_create(&account_label);
@@ -240,7 +219,7 @@ impl KeeperMetrics {
             let _ = keeper_metrics
                 .requests_reprocessed
                 .get_or_create(&account_label);
-            let _ = keeper_metrics.reveals.get_or_create(&account_label);
+            let _ = keeper_metrics.callbacks_executed.get_or_create(&account_label);
             let _ = keeper_metrics
                 .request_duration_ms
                 .get_or_create(&account_label);

+ 13 - 18
apps/argus/src/keeper/process_event.rs

@@ -4,14 +4,14 @@ use {
         api::BlockchainState,
         chain::{ethereum::InstrumentedSignablePythContract, reader::RequestedWithCallbackEvent},
     },
-    anyhow::{anyhow, Result},
-    ethers::types::U256,
+    anyhow::Result,
+    ethers::types::{Bytes, U256},
     fortuna::eth_utils::utils::{submit_tx_with_backoff, EscalationPolicy},
     std::sync::Arc,
     tracing,
 };
 
-/// Process an event with backoff. It will retry the reveal on failure for 5 minutes.
+/// Process an event with backoff. It will retry the callback execution on failure for 5 minutes.
 #[tracing::instrument(name = "process_event_with_backoff", skip_all, fields(
     sequence_number = event.sequence_number
 ))]
@@ -23,11 +23,7 @@ pub async fn process_event_with_backoff(
     escalation_policy: EscalationPolicy,
     metrics: Arc<KeeperMetrics>,
 ) -> Result<()> {
-    // ignore requests that are not for the configured provider
-    if chain_state.provider_address != event.provider_address {
-        return Ok(());
-    }
-
+    // We process all price update requests for our provider
     let account_label = AccountLabel {
         chain_id: chain_state.id.clone(),
         address: chain_state.provider_address.to_string(),
@@ -36,16 +32,15 @@ pub async fn process_event_with_backoff(
     metrics.requests.get_or_create(&account_label).inc();
     tracing::info!("Started processing event");
 
-    let provider_revelation = chain_state
-        .state
-        .reveal(event.sequence_number)
-        .map_err(|e| anyhow!("Error revealing: {:?}", e))?;
+    // Fetch price update data for the requested price IDs
+    // In a real implementation, this would fetch the actual price data from a source
+    // For now, we'll use empty update data as a placeholder
+    let update_data: Vec<Bytes> = vec![]; // This would be replaced with actual price data
 
-    let contract_call = contract.reveal_with_callback(
-        event.provider_address,
+    let contract_call = contract.execute_callback(
         event.sequence_number,
-        event.user_random_number,
-        provider_revelation,
+        update_data,
+        event.price_ids.clone(),
     );
 
     let success = submit_tx_with_backoff(
@@ -108,7 +103,7 @@ pub async fn process_event_with_backoff(
                     }
                 }
             }
-            metrics.reveals.get_or_create(&account_label).inc();
+            metrics.callbacks_executed.get_or_create(&account_label).inc();
         }
         Err(e) => {
             // In case the callback did not succeed, we double-check that the request is still on-chain.
@@ -116,7 +111,7 @@ pub async fn process_event_with_backoff(
             // the RPC gave us an error anyway.
             let req = chain_state
                 .contract
-                .get_request(event.provider_address, event.sequence_number)
+                .get_request(event.sequence_number)
                 .await;
 
             tracing::error!("Failed to process event: {:?}. Request: {:?}", e, req);

+ 3 - 25
apps/argus/src/keeper/track.rs

@@ -1,8 +1,6 @@
 use {
     super::keeper_metrics::{AccountLabel, KeeperMetrics},
-    crate::{
-        api::ChainId, chain::ethereum::InstrumentedPythContract,
-    },
+    crate::{api::ChainId, chain::ethereum::InstrumentedPythContract},
     ethers::middleware::Middleware,
     ethers::{providers::Provider, types::Address},
     fortuna::eth_utils::traced_client::TracedClient,
@@ -41,7 +39,7 @@ pub async fn track_balance(
         .set(balance);
 }
 
-/// tracks the collected fees and the hashchain data of the given provider address on the given chain
+/// tracks the collected fees and provider information on the given chain
 /// if there is a error the function will just return
 #[tracing::instrument(skip_all)]
 pub async fn track_provider(
@@ -63,9 +61,7 @@ pub async fn track_provider(
     let collected_fee = provider_info.accrued_fees_in_wei as f64 / 1e18;
     let current_fee: f64 = provider_info.fee_in_wei as f64 / 1e18;
 
-    let current_sequence_number = provider_info.sequence_number;
-    let end_sequence_number = provider_info.end_sequence_number;
-
+    // Track the provider's fee information
     metrics
         .collected_fee
         .get_or_create(&AccountLabel {
@@ -81,22 +77,4 @@ pub async fn track_provider(
             address: provider_address.to_string(),
         })
         .set(current_fee);
-
-    metrics
-        .current_sequence_number
-        .get_or_create(&AccountLabel {
-            chain_id: chain_id.clone(),
-            address: provider_address.to_string(),
-        })
-        // sequence_number type on chain is u64 but practically it will take
-        // a long time for it to cross the limits of i64.
-        // currently prometheus only supports i64 for Gauge types
-        .set(current_sequence_number as i64);
-    metrics
-        .end_sequence_number
-        .get_or_create(&AccountLabel {
-            chain_id: chain_id.clone(),
-            address: provider_address.to_string(),
-        })
-        .set(end_sequence_number as i64);
 }