diff --git a/README.md b/README.md index 0c5bfd1b5d8..88733444bc6 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ In order to enable the zkevm_ namespace, please add 'zkevm' to the http.api flag ### Supported (remote) - `zkevm_getBatchByNumber` +### Configurable +- `zkevm_getBatchWitness` - concurrency can be limited with `zkevm.rpc-get-batch-witness-concurrency-limit` flag which defaults to 1. Use 0 for no limit. + ### Not yet supported - `zkevm_getNativeBlockHashesInRange` diff --git a/cmd/rpcdaemon/commands/zkevm_api.go b/cmd/rpcdaemon/commands/zkevm_api.go index 16ee3284654..9a5373d7176 100644 --- a/cmd/rpcdaemon/commands/zkevm_api.go +++ b/cmd/rpcdaemon/commands/zkevm_api.go @@ -65,6 +65,8 @@ type ZkEvmAPI interface { GetExitRootTable(ctx context.Context) ([]l1InfoTreeData, error) } +const getBatchWitness = "getBatchWitness" + // APIImpl is implementation of the ZkEvmAPI interface based on remote Db access type ZkEvmAPIImpl struct { ethApi *APIImpl @@ -74,6 +76,17 @@ type ZkEvmAPIImpl struct { config *ethconfig.Config l1Syncer *syncer.L1Syncer l2SequencerUrl string + semaphores map[string]chan struct{} +} + +func (api *ZkEvmAPIImpl) initializeSemaphores(functionLimits map[string]int) { + api.semaphores = make(map[string]chan struct{}) + + for funcName, limit := range functionLimits { + if limit != 0 { + api.semaphores[funcName] = make(chan struct{}, limit) + } + } } // NewEthAPI returns ZkEvmAPIImpl instance @@ -85,7 +98,8 @@ func NewZkEvmAPI( l1Syncer *syncer.L1Syncer, l2SequencerUrl string, ) *ZkEvmAPIImpl { - return &ZkEvmAPIImpl{ + + a := &ZkEvmAPIImpl{ ethApi: base, db: db, ReturnDataLimit: returnDataLimit, @@ -93,6 +107,12 @@ func NewZkEvmAPI( l1Syncer: l1Syncer, l2SequencerUrl: l2SequencerUrl, } + + a.initializeSemaphores(map[string]int{ + getBatchWitness: zkConfig.Zk.RpcGetBatchWitnessConcurrencyLimit, + }) + + return a } // ConsolidatedBlockNumber returns the latest consolidated block number @@ -824,6 +844,18 @@ func (api *ZkEvmAPIImpl) GetBlockRangeWitness(ctx context.Context, startBlockNrO } func (api *ZkEvmAPIImpl) getBatchWitness(ctx context.Context, tx kv.Tx, batchNum uint64, debug bool, mode WitnessMode) (hexutility.Bytes, error) { + + // limit in-flight requests by name + semaphore := api.semaphores[getBatchWitness] + if semaphore != nil { + select { + case semaphore <- struct{}{}: + defer func() { <-semaphore }() + default: + return nil, fmt.Errorf("busy") + } + } + if api.ethApi.historyV3(tx) { return nil, fmt.Errorf("not supported by Erigon3") } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 144a8c8de10..de3387c9782 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -517,6 +517,11 @@ var ( Usage: "RPC rate limit in requests per second.", Value: 0, } + RpcGetBatchWitnessConcurrencyLimitFlag = cli.IntFlag{ + Name: "zkevm.rpc-get-batch-witness-concurrency-limit", + Usage: "The maximum number of concurrent requests to the executor for getBatchWitness.", + Value: 1, + } DatastreamVersionFlag = cli.IntFlag{ Name: "zkevm.datastream-version", Usage: "Stream version indicator 1: PreBigEndian, 2: BigEndian.", diff --git a/eth/ethconfig/config_zkevm.go b/eth/ethconfig/config_zkevm.go index 5efc0421224..a3276772711 100644 --- a/eth/ethconfig/config_zkevm.go +++ b/eth/ethconfig/config_zkevm.go @@ -28,6 +28,7 @@ type Zk struct { L1MaticContractAddress common.Address L1FirstBlock uint64 RpcRateLimits int + RpcGetBatchWitnessConcurrencyLimit int DatastreamVersion int SequencerBlockSealTime time.Duration SequencerBatchSealTime time.Duration diff --git a/turbo/cli/default_flags.go b/turbo/cli/default_flags.go index d9b77ca91d0..c2f1d5a1692 100644 --- a/turbo/cli/default_flags.go +++ b/turbo/cli/default_flags.go @@ -185,6 +185,7 @@ var DefaultFlags = []cli.Flag{ &utils.L1MaticContractAddressFlag, &utils.L1FirstBlockFlag, &utils.RpcRateLimitsFlag, + &utils.RpcGetBatchWitnessConcurrencyLimitFlag, &utils.DatastreamVersionFlag, &utils.RebuildTreeAfterFlag, &utils.IncrementTreeAlways, diff --git a/turbo/cli/flags_zkevm.go b/turbo/cli/flags_zkevm.go index caa6a8d88b9..bd1fc9c1c2c 100644 --- a/turbo/cli/flags_zkevm.go +++ b/turbo/cli/flags_zkevm.go @@ -122,6 +122,7 @@ func ApplyFlagsForZkConfig(ctx *cli.Context, cfg *ethconfig.Config) { L1MaticContractAddress: libcommon.HexToAddress(ctx.String(utils.L1MaticContractAddressFlag.Name)), L1FirstBlock: ctx.Uint64(utils.L1FirstBlockFlag.Name), RpcRateLimits: ctx.Int(utils.RpcRateLimitsFlag.Name), + RpcGetBatchWitnessConcurrencyLimit: ctx.Int(utils.RpcGetBatchWitnessConcurrencyLimitFlag.Name), DatastreamVersion: ctx.Int(utils.DatastreamVersionFlag.Name), RebuildTreeAfter: ctx.Uint64(utils.RebuildTreeAfterFlag.Name), IncrementTreeAlways: ctx.Bool(utils.IncrementTreeAlways.Name), @@ -205,6 +206,7 @@ func ApplyFlagsForZkConfig(ctx *cli.Context, cfg *ethconfig.Config) { checkFlag(utils.L1MaticContractAddressFlag.Name, cfg.L1MaticContractAddress.Hex()) checkFlag(utils.L1FirstBlockFlag.Name, cfg.L1FirstBlock) checkFlag(utils.RpcRateLimitsFlag.Name, cfg.RpcRateLimits) + checkFlag(utils.RpcGetBatchWitnessConcurrencyLimitFlag.Name, cfg.RpcGetBatchWitnessConcurrencyLimit) checkFlag(utils.RebuildTreeAfterFlag.Name, cfg.RebuildTreeAfter) checkFlag(utils.L1BlockRangeFlag.Name, cfg.L1BlockRange) checkFlag(utils.L1QueryDelayFlag.Name, cfg.L1QueryDelay)