Skip to content

Conversation

@SuchitraSwain
Copy link

Chat with Peer Reputation System

  • Implement spam-resistant chat using gossipsub with peer reputation tracking
  • Add comprehensive reputation system with scoring, decay, and persistence
  • Include multi-layered spam detection (rate limiting, content analysis, duplicates)
  • Create interactive demo showing bad actors getting down-scored
  • Add unit tests and comprehensive documentation
  • Demonstrate NAT traversal + peerstore + peer scoring integration

Resolves: #878 (ETH-Delhi Hackathon Implementation)"

@acul71
Copy link
Contributor

acul71 commented Nov 20, 2025

@SuchitraSwain Thanks for using py-libp2p in this chat app.
I tried to run it:

(venv) luca@r17:~/PNL_Launchpad_Curriculum/Libp2p/py-libp2p$ python -m examples.decentralized_chat.spam_demo
2025-11-20 03:45:40,840 [INFO] [spam_demo] Starting Spam Demo for Decentralized Chat
2025-11-20 03:45:40,840 [INFO] [spam_demo] This demo shows how the reputation system handles different peer behaviors
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/luca/Informatica/Learning/PNL_Launchpad_Curriculum/Libp2p/py-libp2p/examples/decentralized_chat/spam_demo.py", line 327, in <module>
    trio.run(run_spam_demo)
    ~~~~~~~~^^^^^^^^^^^^^^^
  File "/home/luca/Informatica/Learning/PNL_Launchpad_Curriculum/Libp2p/py-libp2p/venv/lib/python3.13/site-packages/trio/_core/_run.py", line 2549, in run
    raise runner.main_task_outcome.error
  File "/home/luca/Informatica/Learning/PNL_Launchpad_Curriculum/Libp2p/py-libp2p/examples/decentralized_chat/spam_demo.py", line 286, in run_spam_demo
    alice_task = trio.start_soon(alice.start)
                 ^^^^^^^^^^^^^^^
  File "/home/luca/Informatica/Learning/PNL_Launchpad_Curriculum/Libp2p/py-libp2p/venv/lib/python3.13/site-packages/trio/_deprecate.py", line 166, in __getattr__
    raise AttributeError(msg.format(module_name, name))
AttributeError: module 'trio' has no attribute 'start_soon'

The code uses trio.start_soon(), which doesn't exist. In trio, tasks must be started within a nursery. Fix:

Fix for spam_demo.py

Replace the run_spam_demo() function (lines 260-323) with this corrected version:

async def run_spam_demo():
    """Run the spam demonstration."""
    logger.info("Starting Spam Demo for Decentralized Chat")
    logger.info(
        "This demo shows how the reputation system handles different peer behaviors"
    )

    # Create bots with different behaviors
    bots = [
        ChatBot("Alice", "good", find_free_port()),
        ChatBot("Bob", "good", find_free_port()),
        ChatBot("Spammer", "spam", find_free_port()),
        ChatBot("Flooder", "flood", find_free_port()),
        ChatBot("Duplicator", "duplicate", find_free_port()),
    ]

    # Start the first bot (Alice) in its own task
    alice = bots[0]
    
    async def start_alice():
        await alice.start()
    
    # Use a nursery to manage all bot tasks
    async with trio.open_nursery() as nursery:
        # Start Alice first
        nursery.start_soon(start_alice)
        
        # Wait a bit for Alice to start
        await trio.sleep(2)
        
        # Get Alice's address
        if alice.host is None:
            logger.error("Alice's host is not initialized")
            return
            
        alice_addrs = alice.host.get_addrs()
        alice_addr = f"{alice_addrs[0]}/p2p/{alice.host.get_id()}"
        logger.info(f"Alice's address: {alice_addr}")

        # Start other bots and connect them to Alice
        for bot in bots[1:]:
            async def start_bot(bot=bot):
                await bot.start(alice_addr)
            nursery.start_soon(start_bot)
            await trio.sleep(1)  # Stagger connections

        logger.info(
            "All bots started! Watch how the reputation system handles different behaviors:"
        )
        logger.info("- Alice and Bob: Good behavior, should maintain high reputation")
        logger.info("- Spammer: Sends spam messages, should get down-scored")
        logger.info("- Flooder: Sends too many messages, should get rate-limited")
        logger.info("- Duplicator: Sends duplicate messages, should get penalized")
        logger.info("\nThe demo will run for 2 minutes...")

        # Let the demo run
        await trio.sleep(120)  # 2 minutes

        # Stop all bots
        logger.info("Stopping demo...")
        for bot in bots:
            bot.running = False

        # Cancel all tasks (nursery will handle cleanup)
        nursery.cancel_scope.cancel()

    logger.info("Demo completed!")

Changes

  1. Wrapped all bot starts in a trio.open_nursery() context manager
  2. Replaced trio.start_soon() with nursery.start_soon()
  3. Added a helper function start_alice() to start Alice as a task
  4. Added a check to ensure Alice's host is initialized before getting its address
  5. Used nursery.cancel_scope.cancel() to stop all tasks instead of trying to cancel individual tasks

This matches the trio pattern used elsewhere in the codebase. After applying this fix, the spam demo should run correctly.

@acul71
Copy link
Contributor

acul71 commented Nov 20, 2025

@SuchitraSwain

AI Pull Request Review: PR #1000

PR Title: Feature/decentralized chat reputation
Author: SuchitraSwain
Status: OPEN
URL: #1000


1. Summary of Changes

This PR implements a decentralized chat application with peer reputation system as part of the ETH-Delhi Hackathon implementation. The PR adds:

  • New Example Application: A complete decentralized chat system (examples/decentralized_chat/) with:

    • decentralized_chat.py: Main chat application with interactive user interface
    • peer_reputation.py: Comprehensive peer reputation system with scoring, decay, and persistence
    • spam_demo.py: Demonstration script showing how the system handles different peer behaviors
    • test_reputation.py: Unit tests for the reputation system
  • GossipSub Enhancement: Adds flood_publish parameter to GossipsubParams (though implementation is incomplete - see Issues section)

  • Test Updates: Adds a new test test_flood_publish() in test_gossipsub.py

Related Issues:

  • Resolves: [ETH-Delhi]: Decentralized Chat with Peer Reputation #878 (ETH-Delhi Hackathon Implementation)
    • Issue describes implementing a spam-resistant chat dApp using gossipsub with peer scoring and peerstore for reputation persistence
    • The PR successfully addresses the requirements: NAT traversal, peerstore integration, and peer scoring

Affected Modules:

  • examples/decentralized_chat/ (new module)
  • libp2p/tools/constants.py (GossipsubParams)
  • tests/core/pubsub/test_gossipsub.py (new test)
  • tests/utils/factories.py (factory updates)

Breaking Changes: None

Deprecations: None


2. Branch Sync Status and Merge Conflicts

Branch Sync Status

  • Status: ⚠️ Behind origin/main
  • Details: Branch is 440 commits behind origin/main, 17 commits ahead
  • Recommendation: PR should be rebased or merged with origin/main before merge to ensure compatibility with latest changes

Merge Conflict Analysis

  • Conflicts Detected:Yes - Conflicts detected

Conflicting Files:

  • tests/utils/factories.py

Conflict Summary:

  • File: tests/utils/factories.py
  • Conflict Type: Both branches modified the same function
  • Location: Lines 743-748, 773-778, 797-802 (conflict markers detected)
  • Nature: The PR adds flood_publish parameter to create_batch_with_gossipsub(), while main branch has other changes in the same areas
  • Severity: Medium
  • Resolution: Requires careful merge to preserve both the flood_publish parameter addition and any changes from main branch
  • Impact: The conflicts are in test factory code, so resolution should be straightforward but requires attention to ensure both sets of changes are preserved

Resolution Recommendations:

  • Rebase the PR branch onto origin/main
  • Resolve conflicts in tests/utils/factories.py by:
    1. Ensuring flood_publish parameter is added to function signatures
    2. Ensuring flood_publish is passed through to GossipSub creation
    3. Verifying no other changes from main are lost

3. Strengths

  1. Comprehensive Implementation: The decentralized chat example is well-structured with clear separation of concerns:

    • Reputation system is isolated in its own module
    • Main chat logic is clean and readable
    • Demo script effectively showcases different behaviors
  2. Good Documentation:

    • All modules have clear docstrings
    • Code comments explain key logic
    • README-style comments in __init__.py
  3. Test Coverage: Includes unit tests for the reputation system covering:

    • Initial reputation state
    • Spam violation penalties
    • Positive behavior rewards
    • Rate limiting
    • Message validity checks
    • Trust level classification
    • Reputation decay
    • Spam detection patterns
    • Network statistics
  4. Spam Detection Features: Multi-layered spam detection including:

    • Rate limiting (messages per minute/hour)
    • Content analysis (spam patterns, excessive caps, word repetition)
    • Duplicate message detection
    • Message length limits
  5. Peerstore Integration: Properly integrates with libp2p peerstore for reputation persistence across sessions

  6. User Experience: Interactive chat interface with commands (/stats, /peers, /quit) and color-coded trust indicators


4. Issues Found

Critical

  1. Missing flood_publish Implementation in GossipSub

    • File: libp2p/pubsub/gossipsub.py
    • Line(s): 101-119 (GossipSub.init)
    • Issue: The PR adds flood_publish to GossipsubParams and passes it through factories, but GossipSub.__init__() does not accept this parameter. This causes 31 test failures with TypeError: GossipSub.__init__() got an unexpected keyword argument 'flood_publish'
    • Impact: All tests using create_batch_with_gossipsub() fail, including the new test_flood_publish() test
    • Suggestion:
      • Add flood_publish: bool = False parameter to GossipSub.__init__()
      • Store it as an instance attribute
      • Implement the flood publish logic (if not already implemented, this may require additional work)
    • Test Failures: 31 tests failed, all with the same error pattern
  2. Incorrect Newsfragment Issue Number

  3. Test Import Error

    • File: examples/decentralized_chat/test_reputation.py
    • Line(s): 12
    • Issue: Uses relative import from peer_reputation import ... which fails because the module is not in the Python path. Type checker reports: Could not find import of 'peer_reputation'
    • Impact: Test file cannot be run directly and type checking fails
    • Suggestion: Change to from .peer_reputation import ... or from examples.decentralized_chat.peer_reputation import ...

Major

  1. Type Checking Errors - None Type Handling

    • File: examples/decentralized_chat/decentralized_chat.py, examples/decentralized_chat/spam_demo.py
    • Line(s): Multiple locations
    • Issue: 52 type checking errors related to attributes being typed as None but assigned non-None values. For example:
      • self.host = None but later self.host = new_host(...)
      • self.pubsub = None but later self.pubsub = Pubsub(...)
      • self.reputation_manager = None but later assigned PeerReputationManager(...)
    • Impact: Type checking fails, and the code is not type-safe
    • Suggestion: Use proper type hints:
      from typing import Optional
      self.host: Optional[IHost] = None
      self.pubsub: Optional[Pubsub] = None
      self.reputation_manager: Optional[PeerReputationManager] = None
      Or use assert statements or type narrowing to help the type checker understand these are not None when used.
  2. Type Error in connect_to_peer Method

    • File: examples/decentralized_chat/decentralized_chat.py
    • Line(s): 325
    • Issue: info_from_p2p_addr() expects a Multiaddr but receives a str. Type checker error: Argument 'str' is not assignable to parameter 'addr' with type 'Multiaddr'
    • Suggestion: Convert string to Multiaddr:
      from libp2p import new_host
      from multiaddr import Multiaddr
      maddr = Multiaddr(peer_address)
      maddr = info_from_p2p_addr(maddr)
  3. Implicitly Defined Attributes

    • File: examples/decentralized_chat/spam_demo.py
    • Line(s): 65-81
    • Issue: Attributes like message_interval, spam_messages, flood_messages, etc. are defined in _setup_behavior() method rather than __init__(), causing type checker warnings
    • Suggestion: Declare these attributes in __init__() with proper types, or use __slots__ or type annotations
  4. Incorrect Type Annotation for Optional Parameter

    • File: examples/decentralized_chat/spam_demo.py
    • Line(s): 92
    • Issue: async def start(self, connect_to: str = None) - default None is not assignable to str type
    • Suggestion: Use Optional[str]:
      from typing import Optional
      async def start(self, connect_to: Optional[str] = None):
  5. Incorrect Trio API Usage

    • File: examples/decentralized_chat/spam_demo.py
    • Line(s): 286, 298
    • Issue: trio.start_soon() is not a valid function. Should use nursery.start_soon() within a nursery context
    • Suggestion: Use proper trio nursery pattern:
      async with trio.open_nursery() as nursery:
          nursery.start_soon(alice.start)
          # ...
  6. Duplicate Message Detection Bug

    • File: examples/decentralized_chat/peer_reputation.py
    • Line(s): 549
    • Issue: In check_message_validity(), the code tries to access recent_msg.message_data.decode() but MessageRecord doesn't have a message_data attribute - it only has timestamp, message_length, and topic
    • Impact: This will cause an AttributeError at runtime when checking for duplicates
    • Suggestion: Store the message content in MessageRecord or use a different approach for duplicate detection (e.g., hash of message content)

Minor

  1. Linting Errors - Line Length

    • File: Multiple files in examples/decentralized_chat/
    • Issue: Several lines exceed 88 characters (project's line length limit)
    • Files affected:
      • decentralized_chat.py: Lines 164, 179, 182, 279, 301
      • peer_reputation.py: Lines 71, 135, 137
    • Suggestion: Break long lines to comply with project style (black/isort/ruff)
  2. Missing Type Hints

    • File: examples/decentralized_chat/spam_demo.py
    • Line(s): 705
    • Issue: _setup_behavior() method lacks return type annotation
    • Suggestion: Add -> None return type annotation
  3. Unused Import

    • File: examples/decentralized_chat/spam_demo.py
    • Line(s): 6
    • Issue: asyncio is imported but never used (removed by linter, but should be noted)
  4. Test File Organization

    • File: examples/decentralized_chat/test_reputation.py
    • Issue: Test file is in the examples directory rather than tests/ directory. While not wrong, it's unconventional
    • Suggestion: Consider moving to tests/examples/decentralized_chat/test_reputation.py for consistency with project structure

5. Security Review

  1. Input Validation

    • Risk: User input (username, messages) is not sanitized before JSON encoding
    • Impact: Low - JSON encoding provides some protection, but malicious input could still cause issues
    • Mitigation: Consider adding input validation/sanitization, especially for username field
  2. Peer Identity Verification

    • Risk: The reputation system relies on peer IDs, but there's no explicit verification that messages are actually from the claimed peer
    • Impact: Medium - If message signing is compromised, reputation could be manipulated
    • Mitigation: Ensure strict_signing=True is used (which it is), and verify that gossipsub properly validates message signatures
  3. Rate Limiting Bypass

    • Risk: Rate limiting is per-peer, but a malicious peer could create multiple identities
    • Impact: Medium - Could bypass rate limiting by using multiple peer IDs
    • Mitigation: Consider additional network-level rate limiting or identity verification
  4. Reputation Manipulation

    • Risk: Reputation scores are stored in peerstore, which could potentially be manipulated
    • Impact: Low - Peerstore is local, so manipulation would only affect local node
    • Mitigation: Consider adding integrity checks or cryptographic signatures for reputation data
  5. Message Content Exposure

    • Risk: Message content is logged and could contain sensitive information
    • Impact: Low - This is a demo/example application
    • Mitigation: Consider adding options to disable or sanitize logging in production use

Overall Security Impact: Low to Medium - The implementation is reasonable for an example application, but production use would require additional security hardening.


6. Documentation and Examples

Strengths

  • All modules have comprehensive docstrings
  • Example code is well-commented
  • The demo script (spam_demo.py) serves as both functional code and documentation

Issues

  1. Missing README

    • Issue: The examples/decentralized_chat/ directory lacks a README explaining:
      • How to run the chat application
      • How to run the spam demo
      • How the reputation system works
      • Configuration options
    • Suggestion: Add examples/decentralized_chat/README.md with usage instructions
  2. Missing API Documentation

    • Issue: The reputation system classes and methods lack detailed docstrings explaining:
      • How reputation scores are calculated
      • How decay works
      • What the thresholds mean
      • How to customize the system
    • Suggestion: Expand docstrings with more detailed explanations
  3. Example Usage in Main Documentation

    • Issue: No mention of this example in the main project documentation
    • Suggestion: Add reference to this example in docs/examples.rst or similar

7. Newsfragment Requirement

⚠️ CRITICAL: Newsfragment Issue Mismatch

Recommendation:


8. Tests and Validation

Linting (make lint)

  • Status:Failed (Exit code: 1)
  • Errors Found:
    • Trailing whitespace: Fixed automatically in 4 files
    • Pyupgrade: Fixed automatically (type annotations updated)
    • Ruff (line length): 8 lines exceed 88 characters:
      • decentralized_chat.py: Lines 164, 179, 182, 279, 301
      • peer_reputation.py: Lines 71, 135, 137
    • Black/isort: Applied automatically (formatting fixes)

Type Checking (make typecheck)

  • Status:Failed (Exit code: 1)
  • Errors Found: 52 type errors
    • Import error: test_reputation.py cannot import peer_reputation module
    • None type errors: 32 errors related to attributes typed as None but assigned non-None values
    • Type mismatch errors:
      • info_from_p2p_addr() expects Multiaddr but receives str (2 occurrences)
      • trio.start_soon() doesn't exist (2 occurrences)
      • Implicitly defined attributes (5 occurrences)
      • Optional parameter type issues (1 occurrence)
    • Other errors: Various attribute access errors on potentially None objects

Test Execution (make test)

  • Status:Failed (Exit code: 2)

  • Test Results:

    • Total tests: 1035
    • Passed: 372
    • Failed: 31
    • Skipped: Not reported
    • Error: Not reported separately
  • Failed Tests: All 31 failures are due to the same root cause:

    TypeError: GossipSub.__init__() got an unexpected keyword argument 'flood_publish'
    
  • Failed Test Files:

    • tests/core/pubsub/test_gossipsub.py (multiple tests including new test_flood_publish)
    • tests/core/pubsub/test_gossipsub_backward_compatibility.py (multiple tests)
  • Root Cause: The flood_publish parameter is added to GossipsubParams and passed through factories, but GossipSub.__init__() doesn't accept it.

  • Impact: Critical - All gossipsub tests fail, preventing merge

Documentation Build (make linux-docs)

  • Status: Not run (should be checked)

9. Recommendations for Improvement

Immediate Fixes Required (Blockers)

  1. Fix GossipSub Implementation:

    # In libp2p/pubsub/gossipsub.py, add to __init__:
    def __init__(
        self,
        # ... existing parameters ...
        flood_publish: bool = False,  # Add this
    ) -> None:
        # ... existing code ...
        self.flood_publish = flood_publish  # Add this

    Then implement the actual flood publish logic if needed.

  2. Fix Newsfragment:

    • Create newsfragments/878.feature.rst with appropriate content
    • Resolve whether 713.feature.rst should remain or be merged
  3. Fix Test Import:

    • Change from peer_reputation import ... to from .peer_reputation import ... in test_reputation.py
  4. Fix Type Annotations:

    • Add proper Optional[...] types for attributes that start as None
    • Fix connect_to_peer to use Multiaddr type
    • Fix start() method parameter type
  5. Fix Trio API Usage:

    • Replace trio.start_soon() with proper nursery pattern
  6. Fix Duplicate Detection Bug:

    • Store message content in MessageRecord or use message hash for duplicate detection

Code Quality Improvements

  1. Add Type Hints: Ensure all methods have proper type annotations

  2. Fix Line Length: Break long lines to comply with 88-character limit

  3. Add Assertions: Use type narrowing assertions where attributes are guaranteed to be non-None

  4. Add README: Create comprehensive README for the example

  5. Resolve Merge Conflicts: Rebase and resolve conflicts in tests/utils/factories.py


10. Questions for the Author

  1. Flood Publish Feature: Is flood_publish actually implemented, or is this just adding the parameter for future implementation? The parameter is added but I don't see where it's used in the GossipSub logic.

  2. Issue added flood publishing #713 vs [ETH-Delhi]: Decentralized Chat with Peer Reputation #878: What is the relationship between issue added flood publishing #713 and [ETH-Delhi]: Decentralized Chat with Peer Reputation #878? Should there be two separate newsfragments, or is flood_publish part of the chat reputation feature?

  3. Test Location: Why is test_reputation.py in the examples directory rather than the tests directory? Is this intentional?

  4. Duplicate Detection: The duplicate message detection code references message_data attribute that doesn't exist on MessageRecord. Was this tested? How should duplicate detection work?

  5. Trio Usage: The spam_demo.py uses trio.start_soon() which doesn't exist. Was this tested? What was the intended pattern?

  6. Production Readiness: Is this intended as a production-ready example, or a demonstration/prototype? This affects the level of security hardening needed.


11. Overall Assessment

  • Quality Rating: ⚠️ Needs Work

    • The core implementation is solid and well-structured
    • However, critical bugs prevent tests from passing
    • Type safety issues need to be addressed
    • Documentation could be improved
  • Security Impact: Low to Medium

    • Reasonable for an example application
    • Would need additional hardening for production use
  • Merge Readiness:Not Ready - Needs Fixes

    • Blockers:
      1. GossipSub flood_publish parameter not implemented (31 test failures)
      2. Incorrect newsfragment issue number
      3. Merge conflicts need resolution
      4. Type checking failures (52 errors)
      5. Critical bugs (duplicate detection, trio API usage)
    • Required Before Merge:
      • Fix all test failures
      • Resolve merge conflicts
      • Fix critical bugs
      • Correct newsfragment
      • Address type checking errors (at least the critical ones)
  • Confidence: Medium

    • The implementation approach is sound
    • Most issues are fixable with straightforward changes
    • Some questions remain about design decisions (flood_publish implementation, issue relationships)

Summary

This PR implements a comprehensive decentralized chat example with peer reputation, which is excellent work for a hackathon project. The code structure is clean, the reputation system is well-designed, and the example is educational. However, several critical issues prevent merge:

  1. Incomplete implementation of flood_publish feature causing test failures
  2. Type safety issues that need to be addressed
  3. Critical bugs in duplicate detection and trio usage
  4. Newsfragment mismatch that must be corrected

Once these issues are resolved, this will be a valuable addition to the py-libp2p examples. The reputation system implementation is particularly well done and could serve as a reference for other applications.


Review Date: 2025-01-27

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ETH-Delhi]: Decentralized Chat with Peer Reputation

6 participants