11use super :: { IdentifiedAddress , TraceIdentifier } ;
22use crate :: debug:: ContractSources ;
3- use alloy_primitives:: { Address , map:: HashMap } ;
3+ use alloy_primitives:: {
4+ Address ,
5+ map:: { Entry , HashMap } ,
6+ } ;
47use foundry_block_explorers:: { contract:: Metadata , errors:: EtherscanError } ;
58use foundry_common:: compile:: etherscan_project;
69use foundry_config:: { Chain , Config } ;
@@ -25,7 +28,7 @@ use tokio::time::{Duration, Interval};
2528pub struct ExternalIdentifier {
2629 fetchers : Vec < Arc < dyn ExternalFetcherT > > ,
2730 /// Cached contracts.
28- contracts : HashMap < Address , Metadata > ,
31+ contracts : HashMap < Address , ( FetcherKind , Metadata ) > ,
2932}
3033
3134impl ExternalIdentifier {
@@ -67,8 +70,8 @@ impl ExternalIdentifier {
6770 . contracts
6871 . iter ( )
6972 // filter out vyper files
70- . filter ( |( _, metadata) | !metadata. is_vyper ( ) )
71- . map ( |( address, metadata) | async move {
73+ . filter ( |( _, ( _ , metadata) ) | !metadata. is_vyper ( ) )
74+ . map ( |( address, ( _ , metadata) ) | async move {
7275 sh_println ! ( "Compiling: {} {address}" , metadata. contract_name) ?;
7376 let root = tempfile:: tempdir ( ) ?;
7477 let root_path = root. path ( ) ;
@@ -128,7 +131,7 @@ impl TraceIdentifier for ExternalIdentifier {
128131 // Check cache first.
129132 for & node in nodes {
130133 let address = node. trace . address ;
131- if let Some ( metadata) = self . contracts . get ( & address) {
134+ if let Some ( ( _ , metadata) ) = self . contracts . get ( & address) {
132135 identities. push ( self . identify_from_metadata ( address, metadata) ) ;
133136 } else {
134137 to_fetch. push ( address) ;
@@ -145,9 +148,18 @@ impl TraceIdentifier for ExternalIdentifier {
145148 . map ( |fetcher| ExternalFetcher :: new ( fetcher. clone ( ) , Duration :: from_secs ( 1 ) , 5 ) ) ;
146149 let fetched_identities = foundry_common:: block_on (
147150 futures:: stream:: select_all ( fetchers)
148- . map ( |( address, metadata) | {
149- let addr = self . identify_from_metadata ( address, & metadata) ;
150- self . contracts . insert ( address, metadata) ;
151+ . map ( |( address, value) | {
152+ let addr = self . identify_from_metadata ( address, & value. 1 ) ;
153+ match self . contracts . entry ( address) {
154+ Entry :: Occupied ( mut occupied_entry) => {
155+ if !matches ! ( occupied_entry. get( ) . 0 , FetcherKind :: Etherscan ) {
156+ occupied_entry. insert ( value) ;
157+ }
158+ }
159+ Entry :: Vacant ( vacant_entry) => {
160+ vacant_entry. insert ( value) ;
161+ }
162+ }
151163 addr
152164 } )
153165 . collect :: < Vec < IdentifiedAddress < ' _ > > > ( ) ,
@@ -205,7 +217,7 @@ impl ExternalFetcher {
205217}
206218
207219impl Stream for ExternalFetcher {
208- type Item = ( Address , Metadata ) ;
220+ type Item = ( Address , ( FetcherKind , Metadata ) ) ;
209221
210222 fn poll_next ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
211223 let pin = self . get_mut ( ) ;
@@ -233,7 +245,7 @@ impl Stream for ExternalFetcher {
233245 match res {
234246 Ok ( metadata) => {
235247 if let Some ( metadata) = metadata {
236- return Poll :: Ready ( Some ( ( addr, metadata) ) ) ;
248+ return Poll :: Ready ( Some ( ( addr, ( pin . fetcher . kind ( ) , metadata) ) ) ) ;
237249 }
238250 }
239251 Err ( EtherscanError :: RateLimitExceeded ) => {
@@ -267,10 +279,16 @@ impl Stream for ExternalFetcher {
267279 }
268280}
269281
282+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
283+ enum FetcherKind {
284+ Etherscan ,
285+ Sourcify ,
286+ }
287+
270288#[ async_trait:: async_trait]
271289trait ExternalFetcherT : Send + Sync {
290+ fn kind ( & self ) -> FetcherKind ;
272291 fn invalid_api_key ( & self ) -> & AtomicBool ;
273-
274292 async fn fetch ( & self , address : Address ) -> Result < Option < Metadata > , EtherscanError > ;
275293}
276294
@@ -287,6 +305,10 @@ impl EtherscanFetcher {
287305
288306#[ async_trait:: async_trait]
289307impl ExternalFetcherT for EtherscanFetcher {
308+ fn kind ( & self ) -> FetcherKind {
309+ FetcherKind :: Etherscan
310+ }
311+
290312 fn invalid_api_key ( & self ) -> & AtomicBool {
291313 & self . invalid_api_key
292314 }
@@ -314,6 +336,10 @@ impl SourcifyFetcher {
314336
315337#[ async_trait:: async_trait]
316338impl ExternalFetcherT for SourcifyFetcher {
339+ fn kind ( & self ) -> FetcherKind {
340+ FetcherKind :: Sourcify
341+ }
342+
317343 fn invalid_api_key ( & self ) -> & AtomicBool {
318344 & self . invalid_api_key
319345 }
0 commit comments