EIP-2464 eth/65: 트랜잭션 알림과 조회 ("eth/65: transaction announcements and retrievals")

최종 확정 · 네트워크·노드 · 원문 상태 Final · 2020-01-13 작성

노드 간 트랜잭션 전파에 해시만 먼저 알리고 모르는 것만 골라 받는 메시지 세 종을 추가한 새 프로토콜 버전 eth/65를 도입합니다. 같은 트랜잭션을 모든 피어에게 통째로 반복 전송하던 낭비를 줄입니다.

왜 필요한가

이더리움 노드는 새 블록을 전파할 때 두 가지 방법을 씁니다. 소수의 피어에게는 블록 전체를 보내고, 나머지에게는 해시만 알려 필요하면 받아 가게 합니다. 그런데 트랜잭션에는 이런 이중 장치가 없어서 노드는 연결된 모든 피어에게 트랜잭션 전체를 그대로 보내야 합니다. 피어가 N개면 같은 트랜잭션이 N번 오가는 셈인데, 완벽한 세상이라면 1번이면 충분합니다. 또 두 노드가 새로 연결되면 서로의 트랜잭션 풀을 맞춰야 하는데, 상대가 무엇을 이미 아는지 확인할 방법이 없어 수십에서 수백 MB에 이르는 풀 전체를 통째로 보내야 했습니다. 원문은 트랜잭션 전파가 당시 네트워크 자원을 가장 많이 쓰는 부분이고 그 대부분이 중복 전송으로 낭비된다고 지적하면서 값비싼 교환을 하기 전에 먼저 32바이트 해시로 주고받을 목록을 합의하게 해 전체 운영 대역폭을 최소 한 자릿수 이상 줄이는 것을 목표로 합니다.

무엇이 바뀌나

지금

EIP-2464 이후

누구에게 영향이 있나

심층 설명

NewPooledTransactionHashes (0x08): 해시 알림

아직 블록에 포함되지 않은 트랜잭션의 해시 목록 [hash_0: B_32, hash_1: B_32, ...]을 알리는 메시지입니다. 노드는 상대가 모를 수 있는 모든 트랜잭션을 최대한 알려 주는 것이 바람직합니다. 알릴 수 있는 해시 개수에 프로토콜 위반이 되는 하드캡은 없고 10MB devp2p 패킷 한도만 적용되지만 한 패킷이 연결을 독점하지 않도록 4096개(128KB)가 적정한 묶음으로 제시됩니다. 상대가 모를 법한 해시만 알리는 것이 원칙이되, 풀에 논스 공백이 생기는 것보다는 과하게 알리는 편이 낫다고 명시합니다.

GetPooledTransactions (0x09): 선별 요청

상대 노드의 트랜잭션 풀에서 가져올 트랜잭션을 해시 목록으로 지정하는 요청 메시지입니다. 요청 개수에도 프로토콜 위반이 되는 하드캡은 없지만(10MB devp2p 패킷 한도 제외), 수신 측은 응답에 크기나 처리 시간 기준의 임의 상한을 둘 수 있고 이는 프로토콜 위반으로 간주하면 안 됩니다. 응답받지 못하는 해시로 대역폭이 낭비되는 것을 줄이기 위해 256개가 적정 상한으로 제시됩니다.

PooledTransactions (0x0a): 응답과 순서 규칙

GetPooledTransactions 요청에 대해 로컬 트랜잭션 풀의 트랜잭션들로 응답하는 메시지입니다. 각 항목은 이더리움 주 명세의 트랜잭션 형식을 따릅니다. 응답은 반드시 요청과 같은 순서를 지켜야 하고 없는 트랜잭션은 건너뛰어도 됩니다. 이 규칙 덕분에 응답 크기 한도에 걸렸을 때 요청자는 마지막으로 받은 트랜잭션 이후의 해시는 다시 요청하고 그 앞의 빈자리는 상대에게 없는 것으로 간주할 수 있습니다. 빈 응답은 요청된 해시가 풀에 하나도 없을 때만 허용됩니다. 알린 트랜잭션이 그 사이 블록에 포함되어 나중에 제공하지 못하는 것도 허용됩니다.

왜 풀에 있는 트랜잭션만 다루는가

조회 대상을 트랜잭션 풀로 한정한 것은 의도적입니다. 풀 밖의 트랜잭션은 블록 바디에 수백 개씩 묶여 저장되고 기존 네트워크 조회도 이 구조를 따르는데, 개별 트랜잭션을 디스크에서 직접 꺼내게 허용하면 쓸모 있는 사용처 없이 값비싼 데이터베이스 읽기만 네트워크에 노출됩니다. 디스크에 확정된 트랜잭션은 어차피 블록 안에서 전파되므로, 최악의 경우에도 수백 밀리초 지연에 그칩니다. 해시 알림의 중복 제거도 같은 이유로 풀에서만 수행하고 디스크는 무시합니다. 건강한 네트워크에서는 트랜잭션이 블록 포함보다 훨씬 빨리 전파되므로 새로 알려진 트랜잭션이 이미 디스크에 있는 경우는 사실상 없고 디스크 중복 제거를 피하면 원격 알림을 이용한 DoS 괴롭힘도 막을 수 있습니다. 더 엄밀하게 하려면 최근 블록에 포함된 트랜잭션 집합을 메모리에 유지해 뒤늦은 알림을 걸러 내는 방법이 제시됩니다.

왜 Transactions (0x02)를 재사용하지 않는가

초기 안은 기존 Transactions (0x02) 메시지를 GetPooledTransactions의 응답으로 재사용했습니다. 그러나 노드들이 평소에도 Transactions (0x02)를 가십 브로드캐스트로 끊임없이 주고받기 때문에, 쏟아지는 메시지 중 어느 것이 요청에 대한 실제 응답인지 가려내기 어려워 클라이언트 코드가 복잡해집니다. 별도의 PooledTransactions (0x0a)로 분리하면 이 문제가 사라지고 가십 브로드캐스트에는 의미가 없는 요청 ID 추가 같은 미래의 최적화 여지도 남겨 둘 수 있습니다.

배포 방식: 하드포크 없이 새 버전으로

이 EIP는 eth 프로토콜을 하위 호환되지 않는 방식으로 확장하므로 새 버전 eth/65를 출시해야 합니다. 다만 devp2p가 같은 와이어 프로토콜의 여러 버전을 나란히 운용하는 것을 지원하므로, 업데이트하지 않은 클라이언트는 eth/64를 계속 쓰면 되고 클라이언트 간 배포 조율이 필요 없습니다. 합의 엔진을 바꾸지 않으므로 하드포크도 필요하지 않습니다. 원문 상태는 Final로 확정되어 있습니다.

EIP 원문 · ← EIPs