> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stablenet.network/llms.txt
> Use this file to discover all available pages before exploring further.

# P2P 서버 및 피어 관리

이 문서는 StableNet 노드 간 연결을 관리하는 피어투피어 네트워킹 레이어를 다룹니다. 특히 `p2p.Server` 아키텍처, 피어 라이프사이클 관리, 연결 타입, 프로토콜 멀티플렉싱에 대한 세부사항을 제공합니다.\
피어 발견 메커니즘에 대한 정보는 [발견 메커니즘](/ko/networking/7.2-discovery-mechanisms)을 참조하세요.\
블록체인 동기화 프로토콜에 대한 세부사항은 [체인 동기화](/ko/networking/7.3-chain-synchronization)을 참조하세요.\
프로토콜 핸들러 구현은 [프로토콜 핸들러](/ko/networking/7.4-protocol-handlers)을 참조하세요.

## 서버 아키텍처

P2P 레이어는 모든 피어 연결을 관리하고 StableNet 노드의 핵심 네트워킹 기능을 구현하는 `p2p.Server` 구조체를 중심으로 구성됩니다.\
이 서버는 인바운드 및 아웃바운드 연결을 통합 관리하며, 발견 프로토콜과 프로토콜 핸들러 사이의 중재자 역할을 수행합니다.

### 서버 구조

`Server` 구조체는 다음과 같은 주요 구성 요소를 유지합니다:

| Component   | Type               | Purpose                           |
| ----------- | ------------------ | --------------------------------- |
| `Config`    | `p2p.Config`       | 최대 피어 수, 리슨 주소, 활성 프로토콜 등 네트워크 구성 |
| `localnode` | `*enode.LocalNode` | 로컬 노드의 신원 정보 및 ENR 관리             |
| `listener`  | `net.Listener`     | 인바운드 TCP 연결 수신                    |
| `dialsched` | `*dialScheduler`   | 아웃바운드 연결 시도 스케줄링                  |
| `discmix`   | `*enode.FairMix`   | 여러 발견 소스를 집계                      |
| `ntab`      | `*discover.UDPv4`  | Discovery v4 프로토콜 핸들러             |
| `DiscV5`    | `*discover.UDPv5`  | Discovery v5 프로토콜 핸들러             |
| `nodedb`    | `*enode.DB`        | 영속 노드 데이터베이스                      |

### 서버 구성 및 초기화

서버 초기화 시퀀스는 다음과 같은 단계로 진행됩니다:

1. **`setupLocalNode()`**\
   개인 키를 기반으로 로컬 노드 ID와 ENR을 생성하고 노드 데이터베이스를 초기화합니다.
2. **`setupListening()`**\
   구성된 네트워크 주소에서 TCP 리스너를 시작합니다.
3. **`setupDiscovery()`**\
   Discovery v4/v5 프로토콜을 초기화하고 발견 믹서를 구성합니다.
4. **`setupDialScheduler()`**\
   정적 노드 및 발견 노드를 대상으로 하는 다이얼 스케줄러를 생성합니다.
5. **`run()`**\
   피어 이벤트를 처리하는 서버 메인 이벤트 루프를 시작합니다.
6. **`listenLoop()`**\
   인바운드 연결을 지속적으로 수락합니다.

### 서버 메인 루프

서버의 메인 이벤트 루프는 다음과 같은 역할을 수행합니다:

* 피어 추가 및 제거 이벤트 처리
* 다이얼 스케줄러로부터의 연결 요청 처리
* 종료 신호 수신 시 모든 피어를 정상 종료
* 이벤트 피드로 피어 상태 변경 알림 전파

## 피어 라이프사이클

각 연결된 피어는 연결 상태, 프로토콜 핸들러, 수명 주기 정보를 캡슐화하는 `Peer` 구조체로 표현됩니다.

### 연결 설정 흐름

피어 연결은 다음 흐름을 따릅니다:

1. TCP 연결 수립
2. 암호화 핸드셰이크 수행
3. 프로토콜 핸드셰이크 및 기능 협상
4. 프로토콜 멀티플렉싱 설정
5. 피어 등록 및 이벤트 발생

### 핸드셰이크 프로토콜

연결 설정에는 두 단계의 핸드셰이크가 포함됩니다:

1. **암호화 핸드셰이크** (`doEncHandshake`)\
   RLPX 기반 암호화 채널을 설정합니다.
2. **프로토콜 핸드셰이크** (`doProtoHandshake`)\
   지원 프로토콜 및 버전을 협상합니다.

`protoHandshake` 구조체는 다음 정보를 포함합니다:

| Field        | Type     | Description   |
| ------------ | -------- | ------------- |
| `Version`    | `uint64` | P2P 프로토콜 버전   |
| `Name`       | `string` | 클라이언트 식별 문자열  |
| `Caps`       | `[]Cap`  | 지원 프로토콜 기능 목록 |
| `ListenPort` | `uint64` | 리슨 포트         |
| `ID`         | `[]byte` | 노드 공개 키       |

### 프로토콜 멀티플렉싱

핸드셰이크 이후 서버는 공통으로 지원되는 프로토콜을 매칭하고, 각 프로토콜에 메시지 코드 범위를 할당합니다.

* 기본 P2P 메시지: 코드 0–15
* 첫 번째 매칭된 서브프로토콜: 코드 16부터 시작
* 이후 프로토콜은 이전 프로토콜 길이만큼 오프셋 증가

이 구조를 통해 단일 연결에서 여러 프로토콜 메시지를 안전하게 다룰 수 있습니다.

## 연결 타입 및 관리

P2P 서버는 `connFlag`를 사용하여 연결 타입을 구분합니다:

| Flag               | Value    | Description              |
| ------------------ | -------- | ------------------------ |
| `dynDialedConn`    | `1 << 0` | 발견을 통해 생성된 아웃바운드 연결      |
| `staticDialedConn` | `1 << 1` | 정적 노드로의 아웃바운드 연결         |
| `inboundConn`      | `1 << 2` | 외부에서 들어온 인바운드 연결         |
| `trustedConn`      | `1 << 3` | 신뢰 피어(MaxPeers 제한 초과 가능) |

### 피어 제한 및 용량

기본적인 피어 용량 제어 정책은 다음과 같습니다:

* `MaxPeers`: 전체 피어 수 제한
* `MaxPendingPeers`: 연결 대기 피어 수 제한(방향당 기본 50)
* `DialRatio`: 아웃바운드 피어 비율(기본 1/3)

### 다이얼 스케줄러

`dialScheduler`는 아웃바운드 연결 시도를 관리합니다:

* 최근 다이얼 기록을 유지하여 과도한 재시도를 방지
* 정적 노드를 발견 노드보다 우선 연결
* 최대 다이얼 연결 수 제한 준수
* 지수 백오프를 사용하여 실패한 엔드포인트 재시도 제한

## 피어 작업 및 라이프사이클

### 피어 추가 및 제거

서버는 다음 메서드를 통해 피어 집합을 관리합니다:

| Method                    | Purpose           |
| ------------------------- | ----------------- |
| `AddPeer(node)`           | 정적 피어 추가 및 자동 재연결 |
| `RemovePeer(node)`        | 정적 피어 제거 및 연결 해제  |
| `AddTrustedPeer(node)`    | 신뢰 피어 추가          |
| `RemoveTrustedPeer(node)` | 신뢰 피어 제거          |

### 연결 해제 이유

연결 해제 사유는 `DiscReason` 코드로 기록됩니다:

| Reason                    | Code | Description |
| ------------------------- | ---- | ----------- |
| `DiscRequested`           | 0x00 | 정상 종료       |
| `DiscNetworkError`        | 0x01 | 네트워크 오류     |
| `DiscProtocolError`       | 0x02 | 프로토콜 위반     |
| `DiscUselessPeer`         | 0x03 | 유효하지 않은 피어  |
| `DiscTooManyPeers`        | 0x04 | 피어 수 제한 초과  |
| `DiscAlreadyConnected`    | 0x05 | 중복 연결       |
| `DiscIncompatibleVersion` | 0x06 | 버전 불일치      |
| `DiscInvalidIdentity`     | 0x07 | 잘못된 노드 ID   |
| `DiscQuitting`            | 0x08 | 서버 종료       |
| `DiscSubprotocolError`    | 0x10 | 서브프로토콜 오류   |

### 피어 이벤트 피드

서버는 피어 상태 변화를 `PeerEvent`로 외부에 알립니다:

| Event Type             | Description |
| ---------------------- | ----------- |
| `PeerEventTypeAdd`     | 피어 연결 및 등록  |
| `PeerEventTypeDrop`    | 피어 연결 해제    |
| `PeerEventTypeMsgSend` | 메시지 전송      |
| `PeerEventTypeMsgRecv` | 메시지 수신      |

## Ethereum 백엔드와의 통합

Ethereum 백엔드는 프로토콜 등록 과정을 통해 P2P 서버와 통합됩니다.

통합 흐름은 다음과 같습니다:

1. `eth.Ethereum.Protocols()` – 프로토콜 정의 반환
2. `eth.MakeProtocols()` – eth 서브프로토콜 핸들러 생성
3. `snap.MakeProtocols()` – snap 프로토콜 핸들러 생성(활성화 시)
4. `node.Stack.RegisterProtocols()` – P2P 서버에 등록
5. `handler.Start()` – 프로토콜 메시지 처리 시작

### 백엔드의 P2P 서버 참조

백엔드는 RPC 서비스를 위해 P2P 서버 참조를 유지하며, 이는 다음 용도로 사용됩니다:

* `NetAPI` – 네트워크 정보 조회
* `AdminAPI` – 피어 관리 RPC
* ENR 동적 업데이트

## 구성 플래그

P2P 네트워크 구성에 사용되는 주요 플래그는 다음과 같습니다:

| Flag             | Type   | Default                    | Description    |
| ---------------- | ------ | -------------------------- | -------------- |
| `--maxpeers`     | int    | DefaultConfig.P2P.MaxPeers | 최대 피어 수        |
| `--maxpendpeers` | int    | 0                          | 대기 피어 수 제한     |
| `--port`         | int    | 30303                      | 네트워크 리슨 포트     |
| `--bootnodes`    | string | Network-specific           | 부트스트랩 노드       |
| `--nodekey`      | string | -                          | P2P 노드 키 경로    |
| `--nodekeyhex`   | string | -                          | 테스트용 노드 키(hex) |
| `--nodiscover`   | bool   | false                      | 피어 발견 비활성화     |
| `--netrestrict`  | string | -                          | CIDR 네트워크 제한   |

이 구성 값들은 노드 초기화 과정에서 `SetP2PConfig()` 및 `setNodeKey()`를 통해 적용됩니다.
