11use alloy:: {
2- eips:: eip7702:: constants:: EIP7702_DELEGATION_DESIGNATOR , primitives:: Address ,
2+ eips:: eip7702:: constants:: EIP7702_DELEGATION_DESIGNATOR ,
3+ primitives:: { Address , map:: HashSet } ,
34 providers:: Provider ,
45} ;
56use signet_block_processor:: { AliasOracle , AliasOracleFactory } ;
7+ use std:: sync:: { Arc , RwLock } ;
68
7- /// An [`AliasOracle`] backed by an alloy RPC [`Provider `].
9+ /// An RPC-backed [`AliasOracle`] and [`AliasOracleFactory `].
810///
911/// Checks whether an address has non-delegation bytecode by fetching the
1012/// code at the address via `eth_getCode`. Addresses with no code or with
1113/// EIP-7702 delegation code are not aliased; addresses with any other
1214/// bytecode are.
15+ ///
16+ /// Positive results (address is a contract) are cached in a shared set.
17+ /// Contract status is permanent — an address cannot stop being a
18+ /// contract — so cached positives never go stale. All clones (including
19+ /// those produced by [`AliasOracleFactory::create`]) share the same
20+ /// cache.
21+ ///
22+ /// Querying at `latest` is safe because alias status is stable across
23+ /// blocks: an EOA cannot become a non-delegation contract without a
24+ /// birthday attack (c.f. EIP-3607), and EIP-7702 delegations are
25+ /// excluded by the delegation designator check. Even in the
26+ /// (computationally infeasible ~2^80) birthday attack scenario, the
27+ /// result is a benign false-positive (over-aliasing), never a dangerous
28+ /// false-negative.
1329#[ derive( Debug , Clone ) ]
1430pub struct RpcAliasOracle < P > {
1531 provider : P ,
32+ /// Shared cache of addresses known to be non-delegation contracts.
33+ cache : Arc < RwLock < HashSet < Address > > > ,
34+ }
35+
36+ impl < P > RpcAliasOracle < P > {
37+ /// Create a new [`RpcAliasOracle`] from an alloy provider.
38+ pub fn new ( provider : P ) -> Self {
39+ Self { provider, cache : Arc :: new ( RwLock :: new ( HashSet :: default ( ) ) ) }
40+ }
1641}
1742
1843impl < P : Provider + Clone + ' static > AliasOracle for RpcAliasOracle < P > {
1944 async fn should_alias ( & self , address : Address ) -> eyre:: Result < bool > {
45+ // Check cache first — if we've seen this address as a contract, skip RPC.
46+ if self . cache . read ( ) . expect ( "cache poisoned" ) . contains ( & address) {
47+ return Ok ( true ) ;
48+ }
49+
2050 let code = self . provider . get_code_at ( address) . await ?;
2151 // No code — not a contract.
2252 if code. is_empty ( ) {
@@ -26,36 +56,16 @@ impl<P: Provider + Clone + 'static> AliasOracle for RpcAliasOracle<P> {
2656 if code. starts_with ( & EIP7702_DELEGATION_DESIGNATOR ) {
2757 return Ok ( false ) ;
2858 }
29- // Non-delegation contract — alias it.
59+ // Non-delegation contract — cache and alias it.
60+ self . cache . write ( ) . expect ( "cache poisoned" ) . insert ( address) ;
3061 Ok ( true )
3162 }
3263}
3364
34- /// An [`AliasOracleFactory`] backed by an alloy RPC [`Provider`].
35- ///
36- /// Creates [`RpcAliasOracle`] instances that query the host chain at
37- /// `latest`. This is safe because alias status is stable across blocks:
38- /// an EOA cannot become a non-delegation contract without a birthday
39- /// attack (c.f. EIP-3607), and EIP-7702 delegations are excluded by the
40- /// delegation designator check. Even in the (computationally infeasible
41- /// ~2^80) birthday attack scenario, the result is a benign
42- /// false-positive (over-aliasing), never a dangerous false-negative.
43- #[ derive( Debug , Clone ) ]
44- pub struct RpcAliasOracleFactory < P > {
45- provider : P ,
46- }
47-
48- impl < P > RpcAliasOracleFactory < P > {
49- /// Create a new [`RpcAliasOracleFactory`] from an alloy provider.
50- pub const fn new ( provider : P ) -> Self {
51- Self { provider }
52- }
53- }
54-
55- impl < P : Provider + Clone + ' static > AliasOracleFactory for RpcAliasOracleFactory < P > {
56- type Oracle = RpcAliasOracle < P > ;
65+ impl < P : Provider + Clone + ' static > AliasOracleFactory for RpcAliasOracle < P > {
66+ type Oracle = Self ;
5767
5868 fn create ( & self ) -> eyre:: Result < Self :: Oracle > {
59- Ok ( RpcAliasOracle { provider : self . provider . clone ( ) } )
69+ Ok ( self . clone ( ) )
6070 }
6171}
0 commit comments