PLA-471: Multicall3 aggregation for eth_call batches#4
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements Multicall3 aggregation for batched eth_call requests on EVM networks to reduce latency. Multiple eth_call requests targeting the same block are combined into a single contract call, with automatic fallback to individual requests if aggregation fails.
Changes:
- Added Multicall3 encoding/decoding helpers for aggregating
eth_callbatches - Introduced
multicall3Aggregationconfiguration option (enabled by default) - Implemented batch detection and aggregation logic in HTTP server request handling
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| architecture/evm/multicall3.go | Core Multicall3 ABI encoding/decoding functionality |
| architecture/evm/multicall3_test.go | Comprehensive tests for Multicall3 encoding/decoding |
| common/config.go | Added Multicall3Aggregation config field to EvmNetworkConfig |
| erpc/networks.go | Context-based network rate limit skipping for aggregated requests |
| erpc/networks_skip_rate_limit_test.go | Tests for rate limit skipping context functions |
| erpc/http_server.go | Batch detection and config check before aggregation |
| erpc/http_batch_eth_call.go | Main aggregation handler and fallback logic |
| erpc/http_batch_eth_call_detect_test.go | Tests for batch detection logic |
| erpc/http_batch_eth_call_handle_test.go | Tests for aggregation handler scenarios |
| erpc/http_batch_eth_call_forward_test.go | Tests for fallback forwarding |
| erpc/http_batch_eth_call_helpers_test.go | Test helpers and encoding utilities |
| erpc/http_server_batch_eth_call_test.go | End-to-end integration tests |
| docs/pages/operation/batch.mdx | Documentation for the new feature |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 458c99de29
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Claude finished @0x666c6f's task in 1m 56s —— View job Code Review Complete ✓I've completed a comprehensive review of this PR. Overall, this is a well-implemented feature with excellent test coverage and proper fallback mechanisms. Here are my findings: ✅ Strengths
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comprehensive PR ReviewHigh Priority Issues (2)1. [HIGH] Silent Fallback Without VisibilityFile: When batchInfo, detectErr := detectEthCallBatchInfo(requests, architecture, chainId)
if detectErr != nil {
lg.Debug().Err(detectErr).Msg("eth_call batch detection failed")
}Recommendation: Add metrics and log at Info level for production visibility: if detectErr != nil {
lg.Info().Err(detectErr).
Int("requestCount", len(requests)).
Msg("eth_call batch detection failed, processing individually")
// Consider adding: telemetry.MetricMulticall3FallbackTotal.WithLabelValues("detection_error", architecture, chainId).Inc()
}2. [HIGH] Overly Broad Fallback CriteriaFile:
Recommendation: Be more specific - only fallback when multicall3 contract is unavailable (e.g., check for "contract not found" or "no code at address" in error message). Medium Priority Issues (4)3. [MEDIUM] Debug-Level Logging for All Fallback ScenariosFile: All fallback scenarios are logged at Debug level. In production, operators have no visibility into multicall3 health. Recommendation: Add metrics for monitoring fallback frequency by reason. 4. [MEDIUM] Length Mismatch Should Trigger AlertFile: When Recommendation: Add a specific metric for this error case to enable alerting. 5. [MEDIUM] Error from
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "multicall3-cache-set", | ||
| fmt.Sprintf("network:%s", batchInfo.networkId), | ||
| common.ErrorFingerprint(rec), | ||
| ).Inc() | ||
| lg.Error(). | ||
| Interface("panic", rec). | ||
| Str("stack", string(debug.Stack())). | ||
| Msg("unexpected panic on multicall3 per-call cache-set") | ||
| } | ||
| }() | ||
| defer resp.RUnlock() | ||
| defer resp.DoneRef() | ||
|
|
||
| timeoutCtx, timeoutCtxCancel := context.WithTimeoutCause(network.AppCtx(), 10*time.Second, errors.New("cache driver timeout during multicall3 per-call set")) |
There was a problem hiding this comment.
The error message 'cache driver timeout during multicall3 per-call set' should be 'cache driver timeout during multicall3 per-call cache write' or similar to be more precise about the operation.
| "multicall3-cache-set", | |
| fmt.Sprintf("network:%s", batchInfo.networkId), | |
| common.ErrorFingerprint(rec), | |
| ).Inc() | |
| lg.Error(). | |
| Interface("panic", rec). | |
| Str("stack", string(debug.Stack())). | |
| Msg("unexpected panic on multicall3 per-call cache-set") | |
| } | |
| }() | |
| defer resp.RUnlock() | |
| defer resp.DoneRef() | |
| timeoutCtx, timeoutCtxCancel := context.WithTimeoutCause(network.AppCtx(), 10*time.Second, errors.New("cache driver timeout during multicall3 per-call set")) | |
| "multicall3-cache-write", | |
| fmt.Sprintf("network:%s", batchInfo.networkId), | |
| common.ErrorFingerprint(rec), | |
| ).Inc() | |
| lg.Error(). | |
| Interface("panic", rec). | |
| Str("stack", string(debug.Stack())). | |
| Msg("unexpected panic on multicall3 per-call cache write") | |
| } | |
| }() | |
| defer resp.RUnlock() | |
| defer resp.DoneRef() | |
| timeoutCtx, timeoutCtxCancel := context.WithTimeoutCause(network.AppCtx(), 10*time.Second, errors.New("cache driver timeout during multicall3 per-call cache write")) |
| offsets := make([]uint64, len(calls)) | ||
| // offsetTableSize is derived from len(calls) which is bounded by int, | ||
| // so this conversion to uint64 is safe (always non-negative). | ||
| cur := uint64(offsetTableSize) // #nosec G115 |
There was a problem hiding this comment.
The comment #nosec G115 suppresses a security warning but doesn't explain why the conversion is safe. Consider adding a brief explanation: // #nosec G115 - offsetTableSize is derived from len(calls) which is bounded by int, so conversion is safe
|
Claude finished @0x666c6f's task in 2m 53s —— View job PR Review: Multicall3 Aggregation for eth_call BatchesI've completed a thorough review of this PR. Overall, this is a well-architected feature with strong implementation quality. However, there are critical test failures that must be addressed before merging. 🚨 Critical Issues1. Test Failure: Data Race in Parallel Fallback (BLOCKING)Status: Two tests failing in CI (test run)
Issue: The parallel fallback implementation (commit 7d8d272) introduced a data race. The test mock's Race condition details: Root cause: When fixing the sequential fallback issue, the code was correctly changed to use goroutines ( Fix required: Protect the counter with a mutex in the test: var mu sync.Mutex
var projCalls int
// ...
func(ctx context.Context, project *PreparedProject, network *Network, req *common.NormalizedRequest) (*common.NormalizedResponse, error) {
mu.Lock()
projCalls++
mu.Unlock()
return fallbackResponse(t, req), nil
}
|
|
Claude finished @0x666c6f's task in 5m 55s —— View job PR Review: Multicall3 Aggregation for eth_call Batches ✅I've completed a comprehensive review of this PR. This is an excellent implementation of a complex performance optimization feature with outstanding engineering quality. 🎯 Executive SummaryStatus: ✅ APPROVED - Ready to merge pending CI completion This PR successfully implements Multicall3 aggregation for batched
CI Status: Tests are currently running (in progress for 12+ minutes). Will update when complete. ✅ Strengths1. Excellent Fix to Previous IssuesAll critical issues from previous reviews have been properly addressed: ✅ Data race fixed ( var mu sync.Mutex
projCalls := 0
netCalls := 0
// ...
mu.Lock()
netCalls++
mu.Unlock()✅ Parallel fallback implemented ( ✅ Improved fallback criteria ( ✅ Test coverage for ✅ Better logging and metrics: Info-level logging for fallbacks, comprehensive metrics tracking 2. Robust ArchitectureMulticall3 Batching System (
Configuration Design (
Observability (
3. Comprehensive Test CoverageUnit Tests:
Integration Tests:
Edge Cases Covered:
4. Security & Safety✅ Bounds checking: Prevents buffer overflows in ABI encoding/decoding 5. Performance Optimizations✅ Pre-aggregation cache checking: Avoids unnecessary network calls for cached requests
|
| Category | Rating | Notes |
|---|---|---|
| Architecture | ⭐⭐⭐⭐⭐ | Clean separation, well-designed abstractions |
| Test Coverage | ⭐⭐⭐⭐⭐ | Comprehensive unit + integration tests |
| Error Handling | ⭐⭐⭐⭐⭐ | Robust fallback mechanisms, proper error propagation |
| Documentation | ⭐⭐⭐⭐⭐ | Clear comments, design doc, user-facing docs |
| Observability | ⭐⭐⭐⭐⭐ | Excellent metrics coverage |
| Security | ⭐⭐⭐⭐⭐ | Proper validation, bounds checking, overflow protection |
| Performance | ⭐⭐⭐⭐⭐ | Smart optimizations, parallel execution |
🔍 Verification of Previous Review Feedback
All issues from the Jan 15 comprehensive review have been addressed:
| Issue | Status | Evidence |
|---|---|---|
| [HIGH] Silent fallback without visibility | ✅ Fixed | Info-level logging + metrics (http_batch_eth_call.go:374-378) |
| [HIGH] Overly broad fallback criteria | ✅ Fixed | Specific error patterns (multicall3.go:318-327) |
[MEDIUM] Error from nq.Method() ignored |
✅ Fixed | Proper error handling (http_batch_eth_call.go:208-213) |
| [MEDIUM] Length mismatch logging | ✅ Fixed | Error-level logging + metrics (http_batch_eth_call.go:454-461) |
| [MEDIUM] Debug-level fallback logging | ✅ Fixed | Metrics added for all fallback scenarios |
[MEDIUM] Missing safeUint64ToInt test |
✅ Fixed | Tests added in multicall3_test.go |
| Parallel fallback regression | ✅ Fixed | Goroutines + WaitGroup (http_batch_eth_call.go:148-169) |
| Timestamp ID collisions | ✅ Fixed | Atomic counter + timestamp (multicall3.go:24) |
| Rate limit documentation | ✅ Fixed | Comprehensive comments (http_batch_eth_call.go:126-131) |
📈 Feature Highlights
Network-Level Batching
This implementation goes beyond simple JSON-RPC batch handling - it provides network-level batching across all entry points (HTTP single, HTTP batch, gRPC). This is a sophisticated optimization that:
- Reduces latency: Multiple eth_call requests aggregated into single network roundtrip
- Saves resources: Fewer upstream requests reduce costs and improve cache hit rates
- Maintains compatibility: Automatic fallback ensures no breaking changes
- Respects constraints: Configurable limits prevent abuse and ensure quality of service
Smart Configuration
The Multicall3AggregationConfig provides fine-grained control:
OnlyIfPending: Opt-in batching to avoid adding latency when no batch existsAllowCrossUserBatching: Privacy control for multi-tenant environmentsAllowPendingTagBatching: Safety control for non-finalized blocks- Per-network enablement: Disable for chains without Multicall3 deployment
🚦 CI Status Update
Test run: Still in progress (12+ minutes)
- ⏳
testworkflow: in_progress - ⏳
CodeQL: queued - ⏳
Dependency Review: queued - ✅
Claude Code Review: success ⚠️ Claude Code: action_required (this review)
Note: The long test duration is expected given the extensive test coverage (5000+ lines of test code). Will monitor for completion.
🎯 Recommendation
APPROVED ✅
This PR is ready to merge once CI tests pass. The implementation quality is exceptional:
- ✅ All previous review feedback addressed
- ✅ Comprehensive test coverage
- ✅ Robust error handling and fallback mechanisms
- ✅ Excellent observability through metrics
- ✅ Well-documented code and user-facing documentation
- ✅ Security best practices followed
- ✅ Performance optimizations implemented correctly
The minor cosmetic issues noted above can be addressed in a follow-up PR if desired, but they don't block merging.
Great work on this complex feature! 🎉
Task List:
- Read CLAUDE.md for repository guidelines
- Check CI status for current test results
- Review test files for data race issues
- Review core implementation files
- Check if previous review feedback has been addressed
- Provide comprehensive review feedback
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
erpc/networks.go:1
- The method name
Cache()is inconsistent with the existing methodCacheDal()at line 894, which returns the same field. Consider removing one of these methods to avoid confusion about which to use.
package erpc
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| c.MinWaitMs = 2 | ||
| } | ||
| if c.SafetyMarginMs == 0 { | ||
| c.SafetyMarginMs = min(2, c.MinWaitMs) |
There was a problem hiding this comment.
The default for SafetyMarginMs is min(2, c.MinWaitMs), but when MinWaitMs is 0 (the default), this results in SafetyMarginMs = 0. This may not provide sufficient safety margin. Consider using max(2, min(2, c.MinWaitMs)) or documenting this edge case.
| c.SafetyMarginMs = min(2, c.MinWaitMs) | |
| c.SafetyMarginMs = max(2, min(2, c.MinWaitMs)) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 467cc9edc6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Build the multicall3 request | ||
| mcReq, _, err := BuildMulticall3Request(requests, batch.Key.BlockRef) | ||
| if err != nil { |
There was a problem hiding this comment.
Preserve original block parameter when batching
The multicall request is built with batch.Key.BlockRef as the block parameter, but batch.Key.BlockRef is derived from ExtractCallInfo/NormalizeBlockParam, which normalizes hex block numbers to decimal strings and flattens EIP‑1898 block objects into plain strings. That means a request like "0x10" or {blockHash: ...} becomes "16"/"0x…" in the multicall call, which many JSON‑RPC servers reject because eth_call expects a hex quantity or a block-parameter object. When that happens the multicall call errors and ShouldFallbackMulticall3 won’t treat it as recoverable, so all batched requests fail even though the originals were valid. Consider carrying the original block parameter (or a hex‑normalized equivalent) into the multicall request instead of the normalized key string.
Useful? React with 👍 / 👎.
d651ad5 to
9a8e023
Compare
|
Claude finished @0x666c6f's task in 3m 12s —— View job PR Review: Multicall3 Aggregation for eth_call Batches ✅I've completed a thorough review of this PR. This is an excellent implementation of a sophisticated network-level batching system with outstanding engineering quality. 🎯 Executive SummaryStatus: ✅ APPROVED - High-quality implementation ready to merge This PR implements Multicall3 aggregation for batched CI Status: Tests still in progress (15+ minutes) - will complete shortly
Task List
✅ Strengths1. Exceptional Architecture DesignNetwork-Level Batching (
Clean Separation of Concerns:
Smart Batching Key Design (
2. Comprehensive Test Coverage ⭐⭐⭐⭐⭐8 dedicated test files with excellent coverage:
Critical edge cases tested:
3. Robust Error Handling and FallbackMultiple fallback layers (
Smart fallback criteria (
Parallel fallback (
4. Excellent Observability ⭐⭐⭐⭐⭐11 Prometheus metrics (
Comprehensive logging:
5. Security & Safety✅ Bounds checking (
✅ Integer overflow protection:
✅ Input validation (
✅ Safe memory management:
✅ Thread safety:
6. Performance Optimizations✅ Pre-aggregation cache checking (
✅ Within-batch deduplication (
✅ Smart rate limiting:
✅ Composite type marking (
✅ Async cache writes (
7. Configuration Design ⭐⭐⭐⭐⭐Backward compatible (
Sensible defaults (lines 1595-1624):
Rich configuration options:
Comprehensive validation (
8. All Previous Review Feedback Addressed ✅From Jan 14-15 reviews, ALL issues fixed:
|
| Category | Rating | Notes |
|---|---|---|
| Architecture | ⭐⭐⭐⭐⭐ | Network-level batching across all entrypoints - exceptional design |
| Test Coverage | ⭐⭐⭐⭐⭐ | 3600+ lines of tests, edge cases covered |
| Error Handling | ⭐⭐⭐⭐⭐ | Robust fallback mechanisms, smart retry logic |
| Documentation | ⭐⭐⭐⭐⭐ | Design doc, inline comments, user-facing docs |
| Observability | ⭐⭐⭐⭐⭐ | 11 metrics covering all scenarios |
| Security | ⭐⭐⭐⭐⭐ | Bounds checking, overflow protection, input validation |
| Performance | ⭐⭐⭐⭐⭐ | Pre-aggregation cache, deduplication, async writes |
| Config Design | ⭐⭐⭐⭐⭐ | Backward compatible, sensible defaults, rich options |
🎯 Feature Highlights
Network-Level Batching (Not Just HTTP)
This implementation provides true network-level batching that:
- Works across all entry points: HTTP single requests, HTTP batch requests, gRPC
- Preserves network behaviors: caching, failover, circuit breakers, rate limiting
- Maintains billing accuracy: per-request metrics and rate limits
- Enables deduplication: identical requests share multicall slots
- Respects deadlines: deadline-aware batching prevents timeout issues
Smart Configuration
OnlyIfPending: No latency unless batch already exists (opt-in batching)AllowCrossUserBatching: Privacy control for multi-tenant environmentsAllowPendingTagBatching: Safety for non-finalized blocks- Per-network enablement: Disable for chains without Multicall3
Production-Ready
- Comprehensive metrics for monitoring
- Graceful fallback on failure
- Panic recovery with tracking
- Proper resource cleanup
- Thread-safe implementation
📈 Statistics
- Files changed: 41
- Lines added: 12,119
- Lines deleted: 65
- Test lines: 3,600+
- Commits: 35
- Metrics added: 11
- Test files: 8
🚦 CI Status
Test run: In progress (15+ minutes) - View tests
- ⏳
test: in_progress (expected to pass based on code quality) - ⏳
CodeQL: queued - ⏳
Dependency Review: queued - ✅
Claude Code Review: success ⚠️ Claude Code: action_required (this review)
Note: Long test duration is expected given 3600+ lines of test code. Based on code review, tests should pass.
🎯 Recommendation
✅ APPROVED
This PR is ready to merge once CI tests complete. The implementation is exceptional:
- ✅ All previous review feedback comprehensively addressed
- ✅ Excellent architecture - network-level batching across all entrypoints
- ✅ Comprehensive test coverage with critical edge cases
- ✅ Robust error handling with smart fallback logic
- ✅ Outstanding observability (11 metrics, comprehensive logging)
- ✅ Security best practices (bounds checking, overflow protection)
- ✅ Performance optimizations (caching, deduplication, parallel fallback)
- ✅ Production-ready configuration with backward compatibility
The minor cosmetic observations noted above can be addressed in follow-up PRs if desired, but they don't block merging.
Excellent work on this sophisticated feature! 🎉 This is a significant performance optimization that will benefit all users with batched eth_call workloads.
- Add MetricMulticall3AbandonedTotal metric for tracking context cancellation - Add logging when batch results cannot be delivered due to context cancellation - Release response when context is cancelled to prevent memory leaks - Add build_failed label to fallback metrics when batch building fails - Add forwarder nil validation in NewBatcher (panic on programming error) - Add debug logging for enqueue errors in eth_call.go - Add debug logging for cache get errors in http_batch_eth_call.go - Update tests to use mock forwarder after nil validation was added Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TestBatcher_ShutdownDuringActiveFlush: verifies that shutdown during an active flush delivers shutdown errors to pending entries - Add TestBatcher_DoubleFlushPrevention: verifies that concurrent flush calls on the same batch don't result in double-processing (race test) Both tests run with -race flag to catch any synchronization issues. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add allowedCallFields validation to reject unsupported fields (accessList, etc.) early in IsEligibleForBatching to avoid batcher failures - Add blockParamForMulticall() to normalize block references: - Convert decimal block numbers to hex format - Pass through hex and tag values unchanged - Add test TestBatcherFlush_UsesHexBlockParam to verify block param handling - Add test case for unsupported call field rejection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tcher Critical fixes: - Add panic recovery with stack trace logging to scheduleFlush goroutine - Fix inaccurate comment about map ordering (we iterate entries slice) High priority fixes: - Elevate cache/abandonment logging from Debug to Warn level - Add stack trace logging to fallback panic recovery - Use null byte separator in BatchingKey.String() to prevent collisions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
P1 - Preserve block-hash params:
- Wrap 66-char hex strings (block hashes) in EIP-1898 format {blockHash: ...}
to prevent misinterpretation as block numbers
P2 - Release multicall responses:
- Add mcResp.Release() after decoding and in error/fallback paths
to prevent memory leaks from unreleased response buffers
P2 - Add cache reads for batched eth_call:
- Check cache before enqueueing requests into batcher
- Return cached responses directly, bypassing batching for cache hits
- Prevents performance regression when caching is enabled
P2 - Apply multicall3Aggregation defaults for TS configs:
- Add UnmarshalJSON method with bool backward compatibility
- Ensures {enabled: true} gets proper default values in TypeScript configs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- P2: Mark calls with requireCanonical:false as ineligible for batching (EIP-1898 flag would be lost when rebuilding block param) - P3: Apply default multicall3 config when not explicitly configured (enables batching by default as documented) - Fix error message wording: "cache-set" → "cache write" for consistency - Add test coverage for requireCanonical eligibility checks Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix timer channel drain in scheduleFlush: properly drain timer.C when Stop() returns false to prevent goroutine/memory leaks - Add backpressure for cache write goroutines: use semaphore (100 max) to prevent unbounded goroutine growth under high load; skip cache write gracefully when at capacity - CI already runs tests with -race flag via Makefile Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
P2: Avoid synthetic deadline for no-timeout batches - Don't create synthetic deadline when context has no deadline - Only update flush time based on deadline when request has one - Prevents unnecessary timeouts on upstream multicall calls P2: Reject mixed requireCanonical block-hash params in batch detection - Track requireCanonical state across requests in a batch - Reject batches with mixed values (some true/default, some false) - Treat explicit true and absent (default true) as compatible - Added test cases for requireCanonical handling P3: Record validation errors in request span - Pass actual error to EndRequestSpan instead of processed error body - Ensures validation errors are properly recorded in tracing spans Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CRITICAL fixes: - Add panic recovery in forwardEthCallBatchCandidates goroutines to prevent server crash on unexpected panics - Add MetricMulticall3CacheReadErrorsTotal for cache get errors to improve observability HIGH priority fixes: - Fix response release race condition by removing async release (was using `go resp.Release()`, now uses synchronous release) Tests: - Add TestNewBatcher_NilForwarder_Panics to verify panic on nil forwarder - Add TestBatcher_ScheduleFlush_PanicRecovery to verify panic recovery Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract timer drain helper function (stopAndDrainTimer) - Add BatchingKey.Validate() method for required field validation - Add target address length validation (20 bytes) - Change cache write log level from Debug to Warn - Extract magic number 100 to maxConcurrentCacheWrites constant Tests: - Add TestBatcher_FallbackIndividual_PanicRecovery - Add TestBatcher_MaxQueueSize_Enforcement - Add TestBatchingKey_Validate - Add TestBatcher_InvalidTargetLength_Bypass Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests assumed nil Multicall3Aggregation config would disable batching, but the default config has Enabled: true. Now explicitly set Enabled: false. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the multicall3Aggregation config option for EVM networks, including all available settings: enabled, windowMs, minWaitMs, maxCalls, maxCalldataBytes, maxQueueSize, maxPendingBatches, and allowCrossUserBatching. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new unit tests for multicall3 batcher and HTTP batch handling: - multicall3_batcher_test.go: Add tests for decode errors (nil response, nil JSON-RPC, JSON-RPC error, empty result), EIP-1898 block hash wrapping, context cancellation cleanup, successful delivery, cancelled context handling, and multiple deadline scheduling - http_batch_eth_call_handle_test.go: Add panic recovery test for fallback forward path and empty params handling test - http_batch_eth_call_forward_test.go: Add panic recovery and context cancellation tests for forward goroutines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test was using a non-atomic counter incremented by concurrent goroutines, causing flaky test behavior depending on scheduling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Gosec scanner step was getting cancelled due to the 20-minute timeout after tests completed successfully. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add missing config fields to user docs (safetyMarginMs, onlyIfPending, cachePerCall, allowPendingTagBatching) in networks.mdx - Clarify Multicall3 scope in batch.mdx - works across ALL entrypoints (HTTP single, HTTP batch, gRPC), not just JSON-RPC batch requests - Add metric for tight deadline bypass using MetricMulticall3QueueOverflowTotal with reason "deadline_too_tight" - Remove duplicate CacheDal() method in networks.go (keep Cache() for interface) - Use null byte separator in BatcherManager key to prevent collision risk - Apply code formatting (make fmt) Note: HIGH priority issue "Batch.mu exposed" was a false positive - the mu field is already lowercase (unexported) and only accessible within the evm package. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add explicit error when upstream group filter yields zero upstreams (prevents confusing "upstreams exhausted" error on misconfiguration) - Add tracing attributes for post-filter upstream count and group - Add MetricMulticall3PanicTotal metric for panic recovery tracking (recorded regardless of logger availability) - Add MetricMulticall3CacheWriteDroppedTotal metric for cache write backpressure monitoring Test coverage already exists for: - Concurrent flush + enqueue: TestBatcherConcurrentFlush - Cache write failures: TestBatcher_CacheWriteError_DoesNotFailRequest - Panic recovery: TestBatcher_ScheduleFlush_PanicRecovery Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- When a UseUpstream directive is present, skip the matchUpstreamGroup filtering to allow targeting specific upstreams outside the group - Add matchUpstreamGroup to TypeScript config types (FailsafeConfig) - Add regression tests for group filter / UseUpstream interaction Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add integration test suite that validates multicall3 batching functionality against a real eRPC instance. Tests cover: Core functionality: - JSON-RPC batch aggregation into single multicall3 call - Concurrent request batching within time window - Mixed batches (eth_call + other methods) - Different contract addresses in same batch - Large batches (20+ calls) - Request deduplication Bypass scenarios (calls that should NOT be batched): - Calls with value/from/gas fields - State overrides (3rd param) - Calls to multicall3 contract itself (recursion guard) - requireCanonical:false (EIP-1898) Block reference variations: - Block hash (EIP-1898 format) - finalized/safe/earliest tags - Specific block numbers Input variations: - 'input' field as alternative to 'data' - Empty and large calldata Directive tests: - X-ERPC-Skip-Cache-Read - X-ERPC-Retry-Empty - X-ERPC-Use-Upstream Also includes bash script for production testing. Usage: ERPC_INTEGRATION_TEST_ENDPOINT=http://localhost:4000/main/evm/1 \ ERPC_INTEGRATION_TEST_METRICS=http://localhost:4001/metrics \ ERPC_INTEGRATION_TEST_AUTH="X-ERPC-Secret-Token: token" \ go test -v ./test/integration/... Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Redundant with the Go integration tests which provide better coverage. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds Multicall3Aggregation to the list of EVM config fields that are merged from networkDefaults when a network has its own evm section. This allows disabling multicall3 globally via networkDefaults.evm. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime detection for contracts that revert when called via Multicall3 but succeed when called individually (e.g., contracts checking msg.sender code size like Chronicle Oracle). Features: - New `autoDetectBypass` config option (default: false) - Runtime bypass cache with thread-safe access - Auto-retry reverted calls individually, add to bypass if succeeds - Bounded 30s timeout for retry when original context cancelled - Validation for bypassContracts addresses (40 hex chars) Observability: - `erpc_multicall3_runtime_bypass_total` - contracts auto-detected - `erpc_multicall3_auto_detect_retry_total` - retry outcomes (attempt/detected/same_error) Includes comprehensive tests for: - Auto-detect enabled/disabled scenarios - Concurrent cache access (race-safe) - Config validation for bypass addresses Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fbbba3c to
49184c3
Compare
…call3-aggregation-for-eth_call-batches
Summary
eth_callrequests into a single Multicall3 contract call for reduced latencymulticall3Aggregationconfig option to enable/disable per network (default: enabled)Changes
architecture/evm/multicall3.go: Multicall3 encoding/decoding helperscommon/config.go: AddMulticall3Aggregationconfig fielderpc/http_server.go: Config check before batch aggregationdocs/pages/operation/batch.mdx: Feature documentationConfiguration
🤖 Generated with Claude Code