build(p2p): internalize libp2p as local module
What
Internalize io.github.tronprotocol:libp2p:2.2.7 source code as a new p2p/ gradle submodule, replacing the external Maven dependency. No functional changes to P2P behavior, protocol, or consensus.
Why
Upstream tronprotocol/libp2p activity has been intermittent: the repo saw sparse maintenance from 2023-04 to 2024-10 (0–3 commits/month, several months with no commits), with renewed activity in 2025-03 (v2.2.6) and 2025-08 to 2025-11 (v2.2.7). Cross-repo maintenance creates friction:
- Version coordination overhead: Modifying P2P behavior requires publishing libp2p first, then updating java-tron's dependency version
- Debugging difficulty: IDE cannot jump into external artifact source; requires downloading source JARs
- CI dependency: Build depends on external Maven/JitPack artifact availability
- Industry alignment: geth (go-ethereum) maintains its
p2p/package within the monorepo; this follows the same pattern
Internalization makes future P2P changes a single PR instead of a cross-repo dance, and does not preclude back-porting individual commits to upstream libp2p when appropriate.
Changes
Commit 1: chore(p2p): add libp2p v2.2.7 source as p2p module
- Copy 90 main Java files (including embedded
org.web3jcrypto utils) + 2 proto files + 26 test files fromtronprotocol/libp2ptagv2.2.7 - Create
p2p/build.gradlewith protobuf plugin configuration - Add
p2p/lombok.configto temporarily override root logger field name (logvslogger) - Move example code (
StartApp) tosrc/test/java(not packaged in JAR, but available for reference) - Register module in
settings.gradle, updategradle/verification-metadata.xml
Commit 2: style(p2p): replace log field with logger
- Replace all
@Slf4j-generatedlogreferences withlogger(35 files) to match rootlombok.config(lombok.log.fieldName=logger) - Remove temporary
p2p/lombok.configoverride
Commit 3: build(common): switch from external libp2p to local p2p module
common/build.gradle: replace 17 lines (Maven dependency + 11 exclude rules) with singleapi project(':p2p')- Remove
io.github.tronprotocol:libp2p:2.2.7entry fromgradle/verification-metadata.xml
Commit 4: style(p2p): fix checkstyle violations and enable checkstyle
- Apply
google-java-formatfor bulk formatting (indentation, imports, whitespace) - Manual fixes: lambda indentation, line length wrapping, empty catch blocks, star imports
- Enable checkstyle plugin with proto-generated code excluded (
exclude '**/protos/**') - ~1374 of 1454 violations were from proto-generated code; after exclusion only 80 remained in handwritten code
Commit 5: fix(p2p): address review findings
- Replace
BasicThreadFactory.builder()(requires commons-lang3 3.12+) withnew BasicThreadFactory.Builder()(available since 3.0) to prevent implicit global version upgrade from 3.4 to 3.18.0 - Remove unused
grpc-coredependency; retaingrpc-nettyas Netty transport provider (p2p uses 30+ Netty imports for TCP/UDP but zero gRPC imports) - Remove gRPC protoc plugin from protobuf config (p2p protos define only messages, no services)
- Add
p2p/.gitignoreto exclude proto-generated code for all developers
Commit 6: fix(p2p): replace Math with StrictMath and fix flaky network tests
- Replace
Math.min/maxwithStrictMath.min/maxin 5 files to satisfy CIcheck-mathrule (integer operations, results identical) - Rewrite
NetUtilTest.testGetIPwith mockedURLConnection— original test called 3 external IP services which failed in CI (libp2p's own CI never ran tests with-xtest) - New mock tests cover: valid IP response, connection failure, invalid IP, empty response
- Remove
testExternalIp(covered by mock tests), fixtestGetLanIPto not depend on external connectivity
Commit 7: test(p2p): improve test coverage from 35% to 76%
Add comprehensive unit tests to meet the CI coverage gate (changed files > 60%, overall delta < -0.1%).
- 27 new test files across
connection/,dns/,discover/,utils/web3j,stats,exception, plusP2pServiceandP2pConfig - Exclude proto-generated code from jacoco coverage (consistent with the checkstyle exclusion)
Commit 8: chore(p2p): move tests to framework, introduce example sourceSet
Addresses review feedback from @xxo1shine: align with java-tron's project-wide convention of consolidating module unit tests under framework/src/test/.
- Move 53 unit test files from
p2p/src/test/java/toframework/src/test/java/(+4 fromorg.web3jpackage); 100% git renames, package names preserved - Add
testImplementationfor AWS Route53 + Aliyun DNS SDKs inframework/build.gradle(required by 3 DNS-publish tests moved here; these SDKs areimplementation-scope in:p2pso not transitively visible). Minimal excludes only. - Fix pre-existing flaky
DnsManagerTestNPE by adding@Before initP2pConfig()(test result depended on whether prior tests had leftParameter.p2pConfignon-null) - Drop p2p's
jacocoTestReportblock (no local tests now; coverage is captured by:framework:jacocoTestReport) - Move reference examples (
StartApp,DnsExample1/2,ImportUsing,README.md) to a dedicatedp2p/src/example/sourceSet — compiles for API validation but not packaged inp2p.jarand not executed as tests
Commit 9: fix(p2p): drop duplicate srcDir calls in example sourceSet
Removes the explicit srcDir 'src/example/{java,resources}' calls inside the example sourceSet — Gradle already defaults custom-sourceSet srcDirs to those paths, so the explicit calls duplicate them and broke :p2p:processExampleResources with "Entry README.md is a duplicate" on CI.
Key Design Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Module name | p2p | Matches package org.tron.p2p, geth p2p/ convention, project short-name style (common, crypto, etc.) |
| Proto files | Stay in p2p module | P2P protocol is separate from chain protocol in protocol/; avoids coupling |
| Unit test location | framework/src/test/ | Project convention — actuator, chainbase, consensus, common etc. all keep their unit tests under framework |
| Example code | Dedicated p2p/src/example/ sourceSet | Compiled for API validation, not packaged in jar, not run as tests; preserves passive library usability |
| commons-lang3 | 3.4 (global consistent) | Rewrite builder() → new Builder() (3.0 API) instead of upgrading globally |
| grpc-netty retained | Yes | Provides Netty transitively; same as original libp2p; version auto-aligns with protocol module |
| grpc-core + grpc plugin removed | Yes | p2p protos have no service definitions, zero io.grpc imports in source |
| Checkstyle proto exclude | **/protos/** | Proto-generated code has ~1374 violations; consistent with protocol module approach |
Math → StrictMath | All 5 call sites | CI check-math rule; integer min/max results are identical |
testGetIP mock rewrite | URLConnection mock | Original depended on external services; libp2p CI never ran tests |
Scope
- Does NOT change any P2P protocol behavior or message formats
- Does NOT change consensus rules or transaction validation logic
- Does NOT modify protobuf definitions
- Does NOT require hard fork
- All files importing
org.tron.p2pare unchanged (package name preserved) - Existing nodes upgrading need only
git pulland rebuild - p2p module remains passively usable as a standalone library: self-contained code, default
p2p.jarartifact, examples kept as compilable reference
Known Issues (pre-existing in libp2p)
The following issues exist in the original libp2p v2.2.7 codebase and are NOT introduced by this PR. They will be addressed in follow-up PRs:
Critical:
- Node ID generation uses weak PRNG (
java.util.Randominstead ofSecureRandom) — eclipse attack vector - Handshake lacks cryptographic authentication (self-reported node ID, no signature verification)
- Neighbor injection has no count limit per response
High:
- TOCTOU race in
ChannelManager.handMessage(double onConnect) - DNS sync uses predictable
java.util.Random Algorithm.compressPubKeydrops leading zeros from public key X-coordinate
Medium (from Cubic AI review):
Node.equalscompares byte[] vianew String(id)instead ofArrays.equalsChannel.hashCode()NPE wheninetSocketAddressis nullInterruptedExceptionswallowed in DiscoverServer and PeerClient- Several minor NPE risks and unclosed resources
Test
- p2p module compile + example sourceSet compile: PASS
- Full build: BUILD SUCCESSFUL (~14m, 2780 tests, 0 real failures; 1 pre-existing flaky
testPbftpassed on retry) checkstyleMain+checkstyleTest: PASS for all modules including p2pcheck-math: PASS- Node integration test: FullNode started with mainnet config, P2P handshake protocol verified by message exchange (HelloMessage / TOO_MANY_PEERS / channel close)
- Flaky net tests (PbftMsgHandler, TronStatsManager): confirmed pre-existing, pass on retry