EIP-2976 타입 트랜잭션의 네트워크 전파 (Typed Transactions over Gossip)
최종 확정 · 네트워크·노드 · 원문 상태 Final · 2020-09-13 작성
EIP-2718이 도입한 타입 트랜잭션(Typed Transaction)을 노드 간 통신 규약인 devp2p로 주고받을 수 있게 합니다. 새 형식의 트랜잭션이 네트워크에 실제로 전파될 길을 엽니다.
왜 필요한가
EIP-2718은 하나의 봉투 안에 여러 종류의 트랜잭션을 담을 수 있는 타입 트랜잭션을 도입했습니다. 블록 안에 새 형식의 트랜잭션을 넣을 수 있는 틀은 생긴 것입니다. 그런데 트랜잭션이 블록에 들어가려면 먼저 노드들 사이에 퍼져야 합니다. 이더리움 노드들은 devp2p라는 통신 규약으로 서로 트랜잭션을 주고받는데, 이 규약에는 타입 트랜잭션을 전달하는 방법이 정해져 있지 않았습니다. 전파할 방법이 없으면 누구도 새 형식의 트랜잭션을 실제로 블록에 넣을 수 없습니다. 이 EIP는 devp2p가 타입 트랜잭션을 주고받을 수 있도록 규약을 보완해서 타입 트랜잭션의 이점을 실제로 누릴 수 있게 합니다.
무엇이 바뀌나
지금
- 노드 간 통신 규약 devp2p는 기존 형식(레거시) 트랜잭션만 주고받습니다
- EIP-2718의 타입 트랜잭션은 블록 형식으로는 정의됐지만 네트워크로 전파할 방법이 없습니다
- 새 트랜잭션 형식이 나와도 블록 생산자에게 전달할 길이 없어 실제로 쓸 수 없습니다
EIP-2976 이후
- 타입 트랜잭션을 TransactionType || TransactionPayload 형태 그대로 노드 사이에 주고받습니다
- 새 트랜잭션 타입이 생겨도 devp2p 버전을 올리지 않고 전파를 지원할 수 있습니다
- 모르는 타입이나 규칙에 맞지 않는 내용을 보내는 피어와는 연결을 끊어 스팸을 막습니다
누구에게 영향이 있나
- 클라이언트 팀: 트랜잭션을 다루는 모든 devp2p 메시지에서 레거시 트랜잭션과 타입 트랜잭션을 함께 처리해야 합니다.
- 노드 운영자: 새 타입을 모르는 노드는 그 타입을 받았을 때 피어 연결이 끊기므로, 포크 시점에 맞춰 클라이언트를 업데이트해야 합니다.
- 지갑·앱 개발자: EIP-2718 기반으로 정의되는 새 트랜잭션 형식을 실제 네트워크로 보낼 수 있게 됩니다.
심층 설명
타입 트랜잭션의 전송 형식과 해시
TypedTransaction은 TransactionType과 TransactionPayload를 이어 붙인 바이트 배열입니다. TransactionType은 0부터 0x7f 사이의 부호 없는 8비트 값이고, TransactionPayload는 타입에 따라 해석이 달라지는 불투명한 바이트 배열로, 구체 내용은 각 타입을 정의하는 미래의 EIP가 정합니다. 해시는 TypedTransactionHash = keccak256(TypedTransaction)으로, RLP 인코딩을 거치는 레거시의 keccak256(rlp(LegacyTransaction))과 다르게 계산합니다. TransactionId는 타입 트랜잭션이면 TypedTransactionHash, 레거시면 LegacyTransactionHash를 씁니다. 영수증도 같은 방식으로, TypedReceipt는 TransactionType || ReceiptPayload로 정의됩니다.
모르는 타입을 받았을 때의 동작
어떤 메시지를 통해서든 인식하지 못하는 TransactionType을 받은 클라이언트는 그것을 보낸 피어와 연결을 끊어야 합니다(SHOULD). TransactionPayload가 해당 TransactionType에 유효하지 않은 경우에도 마찬가지로 연결을 끊어야 합니다(SHOULD).
포크 블록 전에는 보낼 수 없음
클라이언트는 새 TransactionType의 트랜잭션을 그 타입을 도입하는 포크 블록 이전에 보내서는 안 됩니다(MUST NOT). 또 포크 블록보다 상당히 이른 시점에 새 타입의 트랜잭션을 보내는 피어와는 연결을 끊을 수 있습니다(MAY). 이 규칙으로 아직 활성화되지 않은 형식이 네트워크에 돌아다니는 것을 막습니다.
바뀌는 프로토콜 메시지
Transactions(0x02), PooledTransactions(0x0a)와 BlockBodies(0x06), NewBlock(0x07)의 트랜잭션 목록은 레거시 트랜잭션과 타입 트랜잭션을 모두 담을 수 있는 Transaction 목록이 됩니다. NewPooledTransactionIds(0x08)와 GetPooledTransactions(0x09)는 TransactionId 목록을 쓰고 Receipts(0x10)의 영수증 목록도 TypedReceipt와 LegacyReceipt를 모두 담을 수 있습니다. 이 변경은 모든 프로토콜 버전에 소급 적용됩니다.
프로토콜이 타입별 내용을 모르게 한 이유
devp2p가 각 타입의 payload 구조까지 알도록 설계할 수도 있었습니다. 하지만 그러면 새 트랜잭션 타입이 나올 때마다 devp2p를 고쳐야 해서 장기적으로 유지 부담이 너무 크다고 저자들은 판단했습니다. 그래서 타입 트랜잭션이 지원된다는 사실만 정의하고 내용의 해석은 각 타입을 정의하는 EIP에 맡겼습니다.
연결 끊기 권고와 DoS 방어
모르는 타입을 보낸 피어를 연결한 채로 두면, 정의되지 않은 TransactionType의 트랜잭션을 계속 보내면서 스팸 차단을 피하는 서비스 거부(DoS) 공격에 노출될 수 있습니다. 또 새 타입이 devp2p로 전파될 시점에는 모든 클라이언트가 그 타입을 알아야 하는 하드 포크가 임박했을 것이 거의 확실하다고 보았습니다. 연결 끊기 권고(SHOULD)를 무시하는 것은 신뢰하는 피어이거나 DoS 위험이 아주 낮은 상황으로 제한해야 합니다.
호환성과 현재 상태
레거시 트랜잭션은 계속 지원되므로 기존 방식으로 만든 트랜잭션은 그대로 쓸 수 있습니다. 이 EIP는 네트워킹 분야의 표준으로 최종 확정(Final)된 상태입니다.