22// SPDX-License-Identifier: LGPL-3.0-only
33
44using System ;
5- using System . Collections . Concurrent ;
5+ using System . Collections . Frozen ;
66using System . Collections . Generic ;
77using System . Linq ;
88using System . Security ;
@@ -68,7 +68,7 @@ public partial class EthRpcModule(
6868 IForkInfo forkInfo ,
6969 ulong ? secondsPerSlot ) : IEthRpcModule
7070{
71- private static readonly ConcurrentDictionary < ForkId , ForkConfig > forkConfigCache = [ ] ;
71+ private static FrozenDictionary < ForkId , ForkConfig > ? forkConfigCache = null ;
7272
7373 protected readonly Encoding _messageEncoding = Encoding . UTF8 ;
7474 protected readonly IJsonRpcConfig _rpcConfig = rpcConfig ?? throw new ArgumentNullException ( nameof ( rpcConfig ) ) ;
@@ -808,6 +808,20 @@ private ResultWrapper<TResult> GetStateFailureResult<TResult>(BlockHeader header
808808 public ResultWrapper < JsonNode > eth_config ( bool showAllForks = false )
809809 {
810810 ForkActivationsSummary forks = forkInfo . GetForkActivationsSummary ( _blockFinder . Head ? . Header ) ;
811+
812+ if ( forkConfigCache is null )
813+ {
814+ ReadOnlySpan < Fork > forkSchedule = forkInfo . GetAllForks ( ) ;
815+ Dictionary < ForkId , ForkConfig > allForks = new ( forkSchedule . Length ) ;
816+
817+ foreach ( Fork scheduledFork in forkSchedule )
818+ {
819+ allForks . Add ( scheduledFork . Id , BuildForkConfig ( scheduledFork , _specProvider ) ) ;
820+ }
821+
822+ forkConfigCache = allForks . ToFrozenDictionary ( ) ;
823+ }
824+
811825 List < ForkConfig > ? allForkConfigs = null ;
812826
813827 if ( showAllForks )
@@ -817,31 +831,23 @@ public ResultWrapper<JsonNode> eth_config(bool showAllForks = false)
817831
818832 foreach ( Fork scheduledFork in forkSchedule )
819833 {
820- allForkConfigs . Add ( BuildForkConfig ( scheduledFork , _specProvider ) ) ;
834+ allForkConfigs . Add ( forkConfigCache [ scheduledFork . Id ] ) ;
821835 }
822836 }
823837
824838 return ResultWrapper < JsonNode > . Success ( JsonNode . Parse ( JsonSerializer . Serialize ( new ForkConfigSummary
825839 {
826- Current = BuildForkConfig ( forks . Current , _specProvider ) ,
827- Next = GetForkConfigOrNull ( forks . Next , _specProvider ) ,
828- Last = GetForkConfigOrNull ( forks . Last , _specProvider ) ,
840+ Current = forkConfigCache [ forks . Current . Id ] ,
841+ Next = forks . Next is null ? null : forkConfigCache [ forks . Next . Value . Id ] ,
842+ Last = forks . Last is null ? null : forkConfigCache [ forks . Last . Value . Id ] ,
829843 All = allForkConfigs
830844 } , UnchangedDictionaryKeyOptions ) ) ) ;
831845
832- static ForkConfig ? GetForkConfigOrNull ( Fork ? fork , ISpecProvider specProvider ) =>
833- fork is null ? null : BuildForkConfig ( fork . Value , specProvider ) ;
834-
835846 static ForkConfig BuildForkConfig ( Fork fork , ISpecProvider specProvider )
836847 {
837- if ( forkConfigCache . TryGetValue ( fork . Id , out ForkConfig config ) )
838- {
839- return config ;
840- }
841-
842848 IReleaseSpec spec = specProvider . GetSpec ( fork . Activation . BlockNumber , fork . Activation . Timestamp ) ;
843849
844- return forkConfigCache [ fork . Id ] = new ForkConfig
850+ return new ForkConfig
845851 {
846852 ActivationTime = fork . Activation . Timestamp is not null ? ( int ) fork . Activation . Timestamp : null ,
847853 ActivationBlock = fork . Activation . Timestamp is null ? ( int ) fork . Activation . BlockNumber : null ,
0 commit comments