EIP-2364 eth/64: 포크ID 핸드셰이크 확장 ("eth/64: forkid-extended protocol handshake")
최종 확정 · 네트워크·노드 · 원문 상태 Final · 2019-11-08 작성
노드끼리 처음 연결할 때 주고받는 인사(핸드셰이크)에 포크ID(forkid)를 추가한 새 통신 규약 eth/64를 도입합니다. 호환되지 않는 노드를 비싼 작업 전에 바로 끊어냅니다.
왜 필요한가
이더리움 노드는 서로 연결해 블록과 데이터를 주고받습니다. 그런데 상대가 나와 같은 네트워크, 같은 업그레이드(포크) 이력을 따르는 노드인지 처음에는 알기 어렵습니다. EIP-2124는 노드의 포크 이력을 짧은 값 하나로 요약한 포크ID를 만들고 검증하는 방법을 정의했지만 그 값을 노드끼리 언제 어떻게 주고받을지는 정하지 않았습니다. 그 결과 호환되지 않는 노드와도 일단 연결이 유지되고, 블록을 받아 작업증명(PoW) 확인, EVM 실행, 상태 재구성 같은 비싼 검증을 해 본 뒤에야 맞지 않는 상대라는 것을 알게 됩니다. 그동안 한정된 피어 자리(peer slot)도 쓸모없는 상대가 차지합니다. 이 EIP는 연결 직후의 핸드셰이크에서 포크ID를 서로 검증해 맞지 않는 노드를 그 자리에서 끊도록 합니다. 각 노드는 자기에게 쓸모 있는 상대에게만 자원을 쓰고, 네트워크 전체로는 서로 다른 체인을 따르는 노드 집단이 분리되어 각자의 체인 유지에 자원을 더 쓸 수 있게 됩니다.
무엇이 바뀌나
지금
- 핸드셰이크에서 프로토콜 버전, 네트워크 ID, 제네시스 해시 등만 확인합니다
- 포크 이력이 다른 노드인지는 블록을 받아 검증해 본 뒤에야 알 수 있습니다
- 호환되지 않는 노드가 피어 자리를 차지한 채 남아 있을 수 있습니다
EIP-2364 이후
- 핸드셰이크의 Status 메시지에 포크ID 필드가 추가됩니다
- 양쪽 노드가 상대의 포크ID를 검증해 호환되지 않으면 즉시 연결을 끊습니다
- 비싼 블록 교환과 검증 전에 쓸모없는 연결이 걸러집니다
누구에게 영향이 있나
- 클라이언트 팀: eth/64 버전을 구현하고 충분히 보급될 때까지 기존 eth/63을 나란히 유지해야 합니다.
- 노드 운영자: 노드가 호환되는 상대에게만 자원을 쓰게 되어 동기화와 피어 관리 효율이 올라갑니다.
- 네트워크 전체: 포크 이력이 다른 노드 집단이 서로 분리되어 각 네트워크의 서비스 품질이 올라갑니다.
심층 설명
Status (0x00) 메시지 재정의
eth/64에서 핸드셰이크용 Status (0x00) 패킷의 끝에 forkid 필드를 추가합니다. 기존 패킷은 [protocolVersion, networkId, td, bestHash, genesisHash]이고 새 패킷은 [protocolVersion, networkId, td, bestHash, genesisHash, forkid]입니다. forkid는 [forkHash: [4]byte, forkNext: uint64] 구조이며 각 필드의 의미는 EIP-2124를 따릅니다. 두 피어가 eth/64로 연결되면 이 갱신된 Status 메시지를 핸드셰이크로 반드시 보내야 하고 각 피어는 상대의 forkid를 검증해 비호환이 감지되면 연결을 끊어야 합니다.
eth/63과의 병행 운영과 하위 호환성
이 변경은 eth 프로토콜 핸드셰이크를 하위 호환이 깨지는 방식으로 바꾸므로 새 버전 eth/64로 배포합니다. 다만 devp2p는 같은 와이어 프로토콜의 여러 버전을 나란히 운영하는 것을 지원하므로, 업데이트하지 않은 클라이언트는 eth/63을 계속 쓸 수 있고 클라이언트 간 일정 조율이 필요 없습니다. eth/64가 구현자들 사이에 충분히 채택될 때까지 기존 eth/63을 함께 살려 두어야 합니다. 합의 엔진을 바꾸지 않으므로 하드포크도 필요하지 않습니다.
디스커버리 프로토콜 광고와의 관계
EIP-2124는 포크ID를 피어 탐색(discovery) 프로토콜에서도 광고하는 것을 언급합니다. 디스커버리 단계에서 검증하면 TCP 연결과 RLPx 암호화 스트림을 만들었다가 eth/64에서 거부되어 허무는 비용을 피할 수 있어 더 효율적입니다. 그러나 디스커버리는 잠재적 피어를 제안하는 것이 목적이라 정보가 오래되었거나 노드가 바뀌었을 수 있어 대략적인 필터링 이후에도 정밀한 확인이 필요합니다. 또 디스커버리에서 forkid를 검증하려면 ENR(EIP-778)과 ENR 확장(EIP-868) 지원이 필요한데 현재 이더리움 네트워크가 이를 의무화하지 않습니다. UDP를 쓸 수 없거나 DNS 디스커버리 같은 다른 방식으로 피어를 찾는 시스템도 연결을 거를 방법이 필요하므로, 핸드셰이크 단계의 검증이 별도로 요구됩니다.
genesisHash 필드를 남겨 둔 이유
forkid의 FORK_HASH에는 제네시스 해시가 체크섬으로 포함되어 있어 forkid 기반 필터링은 제네시스 해시 기반 필터링을 포함하는 상위 집합입니다. 그래서 이 EIP는 원래 핸드셰이크에서 genesisHash 필드를 중복 데이터로 보고 제거했었습니다. 그 결정을 되돌린 이유는 제네시스 해시가 연결 필터링 외의 용도로도 쓰이기 때문입니다. 네트워크 크롤러가 현재 노드를 네트워크별로 분류하는 데 이 값을 씁니다. forkid가 제네시스 해시의 역할을 넘겨받기를 기대하지만 서둘러 중복을 없앨 이유는 없으므로 당분간 둘을 나란히 두고 제3자 인프라가 전환한 뒤 미래 버전에서 제거하기로 했습니다.
테스트와 보안, 현재 상태
포크ID의 계산과 검증에 대한 테스트 케이스는 EIP-2124에 정의된 것을 그대로 사용합니다. 보안 고려 사항은 원문에 없음(None)으로 명시되어 있습니다. 이 EIP는 Standards Track의 Networking 분류이며 상태는 Final로, 명세가 확정되어 더 바뀌지 않습니다. eth/63 자체는 EIP로 명세되지 않았고 ethereum/devp2p GitHub 저장소에서 관리됩니다.