@@ -5,6 +5,7 @@ use std::collections::BTreeMap;
55use std:: time:: Duration ;
66
77use foreign_chain_inspector:: abstract_chain:: inspector:: Abstract ;
8+ use foreign_chain_inspector:: aptos:: inspector:: AptosInspector ;
89use foreign_chain_inspector:: arbitrum:: inspector:: Arbitrum ;
910use foreign_chain_inspector:: base:: inspector:: Base ;
1011use foreign_chain_inspector:: bitcoin:: inspector:: BitcoinInspector ;
@@ -16,11 +17,12 @@ use foreign_chain_inspector::starknet::inspector::StarknetInspector;
1617use foreign_chain_inspector:: {
1718 FanOut , ForeignChainInspectionError , NetworkFingerprint , ProviderFailure ,
1819} ;
20+ use foreign_chain_rpc_interfaces:: aptos:: ReqwestAptosClient ;
1921use mpc_node_config:: { ForeignChainConfig , ForeignChainProviderConfig , ForeignChainsConfig } ;
2022use near_mpc_bounded_collections:: NonEmptyVec ;
2123use near_mpc_contract_interface:: types:: { ForeignChain , ProviderId } ;
2224
23- use crate :: prepare_jsonrpc;
25+ use crate :: { prepare_aptos , prepare_jsonrpc} ;
2426
2527/// One provider's verdict. Anything other than [`ProviderStatus::Healthy`] is unhealthy.
2628#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -91,6 +93,8 @@ impl ProbeReport {
9193/// Each provider is tried up to `max_retries` times, `timeout_sec` per try, and only for as long as
9294/// the failures stay transient. This returns within the largest configured `timeout_sec *
9395/// max_retries`, plus the [`foreign_chain_inspector::RETRY_BACKOFF`] between tries.
96+ ///
97+ /// TODO(#4043): take the inspectors as a dependency instead
9498pub async fn probe_all_providers ( config : & ForeignChainsConfig ) -> ProbeReport {
9599 let probe_attempts = config
96100 . iter_chains ( )
@@ -114,8 +118,20 @@ pub async fn probe_all_providers(config: &ForeignChainsConfig) -> ProbeReport {
114118 } )
115119 . await
116120 }
117- // TODO(#4003): probe Aptos and Sui. Ethereum, Solana and Ton have no inspector, so
118- // there is nothing to probe them with.
121+ ForeignChain :: Aptos => {
122+ let timeout = Duration :: from_secs ( chain_config. timeout_sec . get ( ) ) ;
123+ probe_chain ( chain, chain_config, move |provider| {
124+ let ( url, auth_header) = prepare_aptos ( provider) ?;
125+ Ok ( AptosInspector :: new ( ReqwestAptosClient :: new (
126+ url,
127+ auth_header,
128+ timeout,
129+ ) ) )
130+ } )
131+ . await
132+ }
133+ // TODO(#4003): probe Sui. Ethereum, Solana and Ton have no inspector, so there is
134+ // nothing to probe them with.
119135 _ => rows_of ( chain, chain_config, ProviderStatus :: ProbeNotImplemented ) ,
120136 }
121137 } ) ;
@@ -244,6 +260,11 @@ mod tests {
244260 const CLOSED_PORT_URL : & str = "http://127.0.0.1:9" ;
245261 /// For a chain with no probe: the value is never read, only whether it is set at all.
246262 const ANY_FINGERPRINT : & str = "any-fingerprint" ;
263+ /// Aptos providers reports its chain id as a bare JSON number (`uint8`). The configured fingerprint is
264+ /// the same number as text.
265+ const APTOS_MAINNET : u64 = 1 ;
266+ const APTOS_TESTNET : u64 = 2 ;
267+ const PROVIDER_NAME : & str = "publicnode" ;
247268 /// Bitcoin's genesis block hash, which is what tells its networks apart.
248269 const BITCOIN_MAINNET : & str =
249270 "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" ;
@@ -885,6 +906,68 @@ mod tests {
885906 ) ;
886907 }
887908
909+ async fn mock_ledger_info < ' a > (
910+ server : & ' a httpmock:: MockServer ,
911+ chain_id : u64 ,
912+ ) -> httpmock:: Mock < ' a > {
913+ let body = serde_json:: json!( { "chain_id" : chain_id, "ledger_version" : "1" } ) ;
914+ server
915+ . mock_async ( |when, then| {
916+ when. method ( httpmock:: Method :: GET ) ;
917+ then. status ( 200 ) . json_body ( body) ;
918+ } )
919+ . await
920+ }
921+
922+ #[ tokio:: test]
923+ async fn probe_all_providers__should_report_aptos_on_its_expected_chain_id_as_healthy ( ) {
924+ // Given
925+ let server = httpmock:: MockServer :: start_async ( ) . await ;
926+ mock_ledger_info ( & server, APTOS_MAINNET ) . await ;
927+ let config = ForeignChainsConfig {
928+ aptos : Some ( chain_config (
929+ Some ( & APTOS_MAINNET . to_string ( ) ) ,
930+ one_provider ( PROVIDER_NAME , & server. base_url ( ) ) ,
931+ ) ) ,
932+ ..Default :: default ( )
933+ } ;
934+
935+ // When
936+ let report = probe_all_providers ( & config) . await ;
937+
938+ // Then
939+ assert_eq ! (
940+ must_status_of( & report, ForeignChain :: Aptos , PROVIDER_NAME ) ,
941+ ProviderStatus :: Healthy
942+ ) ;
943+ }
944+
945+ #[ tokio:: test]
946+ async fn probe_all_providers__should_report_aptos_on_another_network_as_wrong_network ( ) {
947+ // Given
948+ let server = httpmock:: MockServer :: start_async ( ) . await ;
949+ mock_ledger_info ( & server, APTOS_TESTNET ) . await ;
950+ let config = ForeignChainsConfig {
951+ aptos : Some ( chain_config (
952+ Some ( & APTOS_MAINNET . to_string ( ) ) ,
953+ one_provider ( PROVIDER_NAME , & server. base_url ( ) ) ,
954+ ) ) ,
955+ ..Default :: default ( )
956+ } ;
957+
958+ // When
959+ let report = probe_all_providers ( & config) . await ;
960+
961+ // Then
962+ assert_eq ! (
963+ must_status_of( & report, ForeignChain :: Aptos , PROVIDER_NAME ) ,
964+ ProviderStatus :: WrongNetwork {
965+ expected: NetworkFingerprint :: new( APTOS_MAINNET . to_string( ) ) ,
966+ observed: NetworkFingerprint :: new( APTOS_TESTNET . to_string( ) ) ,
967+ }
968+ ) ;
969+ }
970+
888971 #[ tokio:: test]
889972 async fn probe_all_providers__should_retry_a_provider_that_refused_with_a_rate_limit_code ( ) {
890973 // Given
0 commit comments