Skip to content

Comments

feat: add param SyncFromInBridges to bridgesyncer#1485

Open
joanestebanr wants to merge 24 commits intodevelopfrom
feat/bridgesyncer_param_to_sync_from_for_bridges-1483
Open

feat: add param SyncFromInBridges to bridgesyncer#1485
joanestebanr wants to merge 24 commits intodevelopfrom
feat/bridgesyncer_param_to_sync_from_for_bridges-1483

Conversation

@joanestebanr
Copy link
Collaborator

@joanestebanr joanestebanr commented Feb 16, 2026

🔄 Changes Summary

This PR adds a new configuration parameter SyncFromInBridges to the bridge syncer that controls whether to extract the FromAddress field for bridge Asset events using debug_traceTransaction.

The parameter supports three modes: "true" (always extract using debug_traceTransaction), "false" (never extract), and "auto" (decide based on BRIDGE component activation).

This allows nodes without archive capability to sync bridge events without the expensive debug tracing operation, while maintaining backward compatibility.

Also improve the case SyncFromInBridges==true (bridgeService) using txReceipt in case of direct call to bridge SC

INTERNAL CHANGE: The compatibility store checker (that validate that contents of DB is compatible with current execution) can update data on DB

⚠️ Breaking Changes

None

📋 Config Updates

New configuration parameter added to both BridgeL1Sync and BridgeL2Sync

[BridgeL1Sync]
SyncFromInBridges = "auto"

[BridgeL2Sync]
SyncFromInBridges = "auto"
  • "true": Always extracts FromAddress (requires archive node with debug_traceTransaction)
  • "false": Never extracts FromAddress (stores NULL, no archive node needed)
  • "auto": Automatically decides based on whether BRIDGE component is active

✅ Testing

  • 🤖 Automatic: [Optional: Enumerate E2E tests]
  • 🖱️ Manual: [Optional: Steps to verify]

🐞 Issues

🔗 Related PRs

  • [Optional: Enumerate related pull requests]

📝 Notes

  • [Optional: design decisions, tradeoffs, or TODOs]

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a configurable SyncFromInBridges parameter to the bridge syncer that controls whether the FromAddress field is extracted for bridge Asset events. The feature enables nodes without archive capability to sync bridge events by optionally skipping the expensive debug_traceTransaction call.

Changes:

  • Introduces SyncFromInBridgesMode configuration with three modes: "true" (always extract), "false" (never extract), and "auto" (extract if BRIDGE component is active)
  • Changes Bridge.FromAddress from common.Address to *common.Address to support NULL values in the database
  • Updates the compatibility check system to allow IsCompatible implementations to return updated data for DB storage
  • Implements parameterized SQL queries for bridge filtering to prevent SQL injection

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
bridgesync/config.go Adds SyncFromInBridgesMode type with validation and resolve logic
bridgesync/processor.go Changes FromAddress to pointer type, adds compatibility validation for SyncFromInBridges, implements parameterized queries
bridgesync/downloader.go Updates ExtractTxnAddresses to conditionally skip FromAddress extraction based on config
bridgesync/bridgesync.go Passes syncFromInBridges parameter through to processor initialization
bridgesync/backfill_tx_sender.go Updates backfill logic to respect syncFromInBridges flag
db/compatibility/types/comparer.go Updates IsCompatible interface to return optional update data
db/compatibility/compatibility_db_contents.go Adds logic to update DB when IsCompatible returns non-nil data
bridgeservice/types/types.go Changes BridgeResponse.FromAddress to nullable pointer with documentation
bridgeservice/utils.go Updates response conversion to handle nullable FromAddress
config/default.go Sets default value of SyncFromInBridges = "auto" for both L1 and L2 configs
cmd/run.go Resolves SyncFromInBridges mode based on active components and passes to bridge sync constructors
test/helpers/e2e.go Updates test helpers to pass syncFromInBridges parameter
Multiple test files Updates tests to use pointer-based FromAddress and adds syncFromInBridges parameter
bridgesync/migrations/migrations_test.go Updates migration tests to reflect pointer-based field types
sync/evmdriver.go Updates RuntimeData.IsCompatible signature to match new interface
multidownloader/storage/compatibility_runtime.go Updates DBRuntimeData.IsCompatible to match new interface
aggsender/db/aggsender_db_storage.go Updates RuntimeData.IsCompatible to match new interface
Comments suppressed due to low confidence (1)

bridgesync/processor_test.go:2193

  • Missing test coverage for SyncFromInBridges compatibility logic: The TestBridgeSyncRuntimeData_IsCompatible test doesn't include any test cases for the new SyncFromInBridges field. Consider adding test cases for:
  1. Storage has nil SyncFromInBridges (old DB) and runtime has false - should update DB
  2. Storage has nil SyncFromInBridges (old DB) and runtime has true - should update DB
  3. Storage has false and runtime has true - should return error (incompatible)
  4. Storage has true and runtime has false - should log warning but succeed
  5. Storage has true and runtime has true - should succeed
  6. Storage has false and runtime has false - should succeed

These cases test the compatibility validation logic in processor.go lines 639-665.

func TestBridgeSyncRuntimeData_IsCompatible(t *testing.T) {
	tests := []struct {
		name        string
		current     BridgeSyncRuntimeData
		storage     BridgeSyncRuntimeData
		expectError bool
		errorMsg    string
	}{
		{
			name: "compatible versions",
			current: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(1),
			},
			storage: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(1),
			},
			expectError: false,
		},
		{
			name: "incompatible versions - different DB versions",
			current: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(2),
			},
			storage: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(1),
			},
			expectError: true,
			errorMsg:    "database schema version mismatch",
		},
		{
			name: "incompatible versions - different chain IDs",
			current: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(1),
			},
			storage: BridgeSyncRuntimeData{
				ChainID:   2,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(1),
			},
			expectError: true,
			errorMsg:    "chain ID mismatch: 1 != 2",
		},
		{
			name: "incompatible versions - different addresses",
			current: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x123")},
				DBVersion: intPtr(1),
			},
			storage: BridgeSyncRuntimeData{
				ChainID:   1,
				Addresses: []common.Address{common.HexToAddress("0x456")},
				DBVersion: intPtr(1),
			},
			expectError: true,
			errorMsg:    "addresses[0] mismatch: 0x0000000000000000000000000000000000000123 != 0x0000000000000000000000000000000000000456",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := tt.current.IsCompatible(tt.storage)

			if tt.expectError {
				require.Error(t, err)
				require.Contains(t, err.Error(), tt.errorMsg)
			} else {
				require.NoError(t, err)
			}
		})
	}
}

@joanestebanr joanestebanr force-pushed the feat/bridgesyncer_param_to_sync_from_for_bridges-1483 branch 3 times, most recently from 7613d98 to bb3599f Compare February 17, 2026 15:54
@agglayer agglayer deleted a comment from claude bot Feb 18, 2026
@joanestebanr joanestebanr force-pushed the feat/bridgesyncer_param_to_sync_from_for_bridges-1483 branch from 630c081 to 5ab9317 Compare February 18, 2026 08:47
@joanestebanr
Copy link
Collaborator Author

@claude

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @joanestebanr's task in 2m 2s —— View job


Code Review Complete ✅

I've completed a comprehensive review of this PR. Here's my analysis:


🚀 What's New

This PR introduces a configurable SyncFromInBridges parameter that controls whether the expensive debug_traceTransaction call is used to extract the FromAddress field for bridge Asset events. The feature supports three modes ("true", "false", "auto") and enables nodes without archive capability to sync bridge events. Additionally, it improves performance when SyncFromInBridges==true by using transaction receipts for direct bridge contract calls, and updates the compatibility checker system to allow database updates during validation.

🐛 Bug Fixes

  • Improved FromAddress extraction logic to use txReceipt for direct bridge contract calls (bridgesync/downloader.go:195-199)
  • Fixed SQL injection vulnerabilities by implementing parameterized queries (bridgesync/processor.go)

📋 Config Updates

New configuration parameter added to both BridgeL1Sync and BridgeL2Sync:

[BridgeL1Sync]
SyncFromInBridges = "auto"  # Options: "true", "false", "auto" (default: "auto")

[BridgeL2Sync]
SyncFromInBridges = "auto"
  • "true": Always extracts FromAddress (requires archive node with debug_traceTransaction)
  • "false": Never extracts FromAddress (stores NULL, no archive node needed)
  • "auto": Automatically decides based on whether BRIDGE component is active

⚠️ Breaking Changes

  • Database Schema: Bridge.FromAddress changed from common.Address to *common.Address (nullable). Existing databases are automatically updated via compatibility checker.
  • API Response: BridgeResponse.FromAddress is now nullable (*Address) in bridge service responses

🔍 Detailed Review Findings

🔴 Required (Security/Bugs)

  1. Empty String Handling in Config (bridgesync/config.go:32)

    • Issue: Empty string returns error instead of defaulting to "auto" as documented
    • Impact: Config validation fails if field is omitted or empty
    • Recommendation: The current behavior appears intentional based on PR author's comment. However, documentation should clarify that empty values are invalid.
    • Location: bridgesync/config.go:32
  2. Potential Nil Pointer Dereference (bridgesync/processor.go:642)

    • Issue: b.SyncFromInBridges is dereferenced without nil check in compatibility validation
    • Impact: Could panic if called in unexpected contexts (though unlikely in production)
    • Recommendation: Add defensive nil check or document assumption
    • Code:
    if storage.SyncFromInBridges == nil {
        // ... uses *b.SyncFromInBridges without nil check
  3. Incomplete Test Coverage for SyncFromInBridges Compatibility (bridgesync/processor_test.go)

    • Issue: TestBridgeSyncRuntimeData_IsCompatible doesn't test all SyncFromInBridges compatibility scenarios
    • Missing test cases:
      • Storage has nil SyncFromInBridges (old DB) + runtime has false → should update DB
      • Storage has nil SyncFromInBridges + runtime has true → should update DB
      • Storage has false + runtime has true → should return error (forbidden)
      • Storage has true + runtime has false → should succeed with warning
      • Both true/both false → should succeed
    • Impact: Complex compatibility logic (processor.go:643-670) is not fully validated
    • Recommendation: Add comprehensive test cases as shown in copilot's review comment
    • Location: bridgesync/processor_test.go:2112

🟡 Suggested (Code Quality)

  1. Comment Clarity (bridgesync/processor.go:644-645)

    • Issue: Comment "If store doesn't have this field means that is 'true' by default" could be clearer
    • Recommendation:
    // If storage doesn't have this field, the database was created before this field existed,
    // so we assume 'true' by default (historical behavior).
  2. Grammar Issue in Comment (bridgesync/processor.go:193)

  3. Duplicate Comment (db/compatibility/types/comparer.go:6-9)

🟢 Optional (Style/Alternative Approaches)

  1. AddressMeddler Complexity

    • Observation: The nullable address handling in AddressMeddler (db/meddler.go:227-291) is well-implemented but adds complexity
    • Alternative: Could consider using sql.NullString wrapper, but current approach is consistent with existing patterns
    • Impact: None - current implementation works correctly
  2. Config Validation Logic

    • Observation: Empty string validation (config.go:103) is strict
    • Alternative: Could default empty strings to "auto", but current strict validation is defensible
    • Impact: None - forces explicit configuration

✅ Positive Aspects

  1. Excellent Architecture: The three-mode system ("true"/"false"/"auto") provides great flexibility
  2. Performance Optimization: Direct bridge call detection (downloader.go:195-199) is a smart optimization
  3. Backward Compatibility: The compatibility checker updates old databases automatically without breaking changes
  4. Security Improvements: SQL injection vulnerabilities fixed with parameterized queries
  5. Comprehensive Testing: Strong test coverage (82.1%) with thorough e2e tests
  6. Clear Documentation: Config parameter is well-documented with examples

📊 Test Coverage Analysis

SonarQube Results: ✅ Quality Gate Passed

  • New issues: 3 (all addressed in review)
  • Coverage: 82.1% on new code
  • Security hotspots: 0
  • Code duplication: 0.4%

Test Quality:

  • E2E tests cover all three modes effectively
  • Config validation tests are comprehensive (config_test.go)
  • Migration tests updated appropriately
  • Gap: SyncFromInBridges compatibility logic needs additional test cases (see Required Add UTs for lastgersync #3)

🎯 Recommendations Summary

Must Address Before Merge:

  1. Add comprehensive test cases for SyncFromInBridges compatibility validation logic
  2. Document or add nil check for b.SyncFromInBridges in processor.go:642

Should Address:

  1. Improve comment clarity in processor.go:644-645
  2. Fix grammar issue in processor.go:193
  3. Remove duplicate comment in comparer.go

Nice to Have:

  1. Consider documenting why empty string doesn't default to "auto" in config validation

🏆 Overall Assessment

This is a high-quality PR that successfully achieves its goals:

  • ✅ Enables nodes without archive capability to sync bridge events
  • ✅ Maintains backward compatibility through smart DB migration
  • ✅ Improves performance with direct call detection
  • ✅ Fixes SQL injection vulnerabilities
  • ✅ Provides flexible configuration with sensible defaults

The implementation is well-thought-out with good test coverage. The main improvement needed is additional test coverage for the SyncFromInBridges compatibility logic.

Recommendation: Approve after addressing Required items #1 and #2.


| Branch: feat/bridgesyncer_param_to_sync_from_for_bridges-1483

@joanestebanr joanestebanr force-pushed the feat/bridgesyncer_param_to_sync_from_for_bridges-1483 branch from 8c8a5b6 to 74821ba Compare February 19, 2026 09:42
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants