eth는 RLPx 전송에서 실행되는 프로토콜로, 피어 간에 이더리움 블록체인 정보를 교환하는 기능을 합니다. 현재 프로토콜 버전은 eth/68이므로 이를 기준으로 분석한 문서이다. devp2p를 보고 정리했다.


Basic Operation


연결 설정: 연결이 설정되면 Status 메시지를 전송해야 하며, 상대 피어로부터 Status 메시지를 수신하면 이더리움 세션이 활성화됩니다. 이후 다른 모든 메시지를 보낼 수 있습니다.

세션 내 작업 : 세션 내에서 세 가지 high-level task(chain synchronization, block propagation and transaction exchange)가 수행됩니다. 각 작업은 별도의 프로토콜 메시지 집합(disjoint sets)를 사용하며, 클라이언트는 모든 피어 연결에서 이 작업들을 동시에 수행합니다.

프로토콜 메시지 크기 제한 : 클라이언트는 프로토콜 메시지 크기에 대한 제한을 적용해야 합니다. RLPx 전송에서는 단일 메시지 크기를 16.7MiB로 제한하지만, 실제로 eth 프로토콜에서는 보통 10MiB로 제한됩니다. 수신된 메시지가 이 한계를 초과하면 피어 연결을 끊어야 합니다.

소프트 한계 : 수신된 메시지에 대한 강력한 제한 외에도, 클라이언트는 전송하는 요청과 응답에 대해 '소프트' 한계를 설정해야 합니다. 메시지 유형에 따라 권장되는 소프트 한계가 다릅니다. 이러한 한계는 블록 동기화와 트랜잭션 교환이 동일한 피어 연결에서 원활하게 이루어지도록 돕습니다.

그럼 이제 3가지 High-Level task들을 살펴보자


Chain Synchronization


  • eth 프로토콜에 참여하는 노드는 제네시스 블록부터 현재 최신 블록까지의 모든 블록에 대한 정보를 알고 있어야 하며, 이를 다른 피어로부터 다운로드하여 얻습니다.
  • 연결이 설정되면, 양쪽 피어는 자신의 ‘best' 블록의 총 난이도(Total Difficulty, TD)와 해시를 포함한 Status 메시지를 서로 전송합니다.
  • 체인 동기화 : 난이도가 더 낮은(worst) 클라이언트는 GetBlockHeaders 메시지를 통해 블록 헤더를 다운로드합니다. 받은 헤더에서 작업 증명(PoW) 값을 확인한 후, GetBlockBodies 메시지를 사용하여 블록 본문을 다운로드합니다. 이 후, 이더리움 가상 머신(Ethereum Virtual Machine)을 사용해 블록을 실행하여 상태 트리(state tree)와 영수증(receipts)을 재생성합니다.
  • 동시 작업 : 헤더 다운로드, 블록 본문 다운로드, 블록 실행은 동시에 발생할 수 있습니다.

State Synchronization (a.k.a “fast sync”)


  • 상태 트리 동기화 : 프로토콜 버전 eth/63부터 eth/66까지는 상태 트리 동기화를 허용했습니다. 그러나 eth/67부터는 이더리움 상태 트리를 eth 프로토콜을 통해 더 이상 검색할 수 없으며, 상태 다운로드는 보조 프로토콜인 snap 프로토콜을 통해 이루어집니다.
  • 상태 동기화 과정 : 상태 동기화는 일반적으로 블록 헤더 체인을 다운로드하고 그 유효성을 검증하는 과정으로 진행됩니다. 블록 본문은 체인 동기화와 마찬가지로 요청되지만, 트랜잭션은 실행되지 않고 '데이터 유효성'만 확인됩니다.
  • 피벗 블록 선택 : 클라이언트는 체인 헤드 근처의 블록(pivot block)을 선택하고 해당 블록의 상태를 다운로드합니다.

Block Propagation


이 내용은 과거 PoW 및 PoA 환경에서의 블록 전파 방식과 관련된 설명이며, 현재 PoS로 전환된 상태에서는 더 이상 유효하지 않음을 참고로 알아두시면 됩니다.


  • PoW에서 PoS로의 전환 : PoW에서 PoS로 전환(The Merge)된 후에는 블록 전파가 더 이상 eth 프로토콜에 의해 처리되지 않습니다. 아래 설명은 과거 PoW 및 PoA(clique) 네트워크에만 적용되며, 블록 전파 메시지(NewBlock, NewBlockHashes 등)는 향후 프로토콜 버전에서 제거될 예정입니다. 현재 PoS로 전환된 eth/68 버전에서는 이 기능이 더 이상 필요하지 않습니다.
  • 블록 전파(Block Propagation) : 새로 채굴된 블록은 모든 노드에 전달되어야 하며, 이는 2단계로 이루어집니다. 피어로부터 NewBlock 메시지를 수신하면, 클라이언트는 작업 증명(PoW) 값이 유효한지 확인하여 블록의 기본 헤더 유효성을 먼저 확인합니다. 그런 다음 NewBlock 메시지를 사용해 연결된 일부 피어(일반적으로 피어 수의 제곱근)에 블록을 전송합니다.
  • 블록 처리 : 헤더 유효성 검사 후, 클라이언트는 블록에 포함된 모든 트랜잭션을 실행하고, 블록의 'Post State'를 계산하여 로컬 체인에 블록을 추가합니다. 이때 블록의 state root 해시는 계산된 Post State root와 일치해야 합니다. 블록이 완전히 처리되고 유효하다고 판단되면, 클라이언트는 이전에 알리지 않은 모든 피어에게 NewBlockHashes 메시지를 보냅니다. 블록을 받지 못한 피어는 전체 블록을 요청할 수 있습니다.
  • 정보 중복 전송 방지 : 노드는 이전에 블록을 알린 피어에게 다시 정보를 보내지 않도록 해야 합니다. 이를 위해 각 피어와 최근에 공유된 블록 해시 세트를 저장하여 중복 전송을 방지합니다.
  • 체인 동기화 유발 가능성 : 블록 알림을 수신한 후, 해당 블록이 클라이언트의 최신 블록의 즉각적인 후속 블록이 아닌 경우, 체인 동기화를 유발할 수도 있습니다.

Transaction Exchange


  • 트랜잭션 교환 : 모든 노드는 채굴자에게 중계하기 위해 대기 중인 트랜잭션을 서로 교환하며, 채굴자는 이를 선택하여 블록체인에 포함시킵니다. 각 클라이언트는 '트랜잭션 풀'에서 대기 중인 트랜잭션을 관리하며, 이 풀에는 수천 개의 트랜잭션이 포함될 수 있습니다.
  • 피어 연결 시 동기화 : 새로운 피어 연결이 설정되면, 양쪽의 트랜잭션 풀을 동기화해야 합니다. 초기에는 양측이 로컬 풀에 있는 모든 트랜잭션 해시를 포함한 NewPooledTransactionHashes 메시지를 교환하여 동기화를 시작합니다.
  • 트랜잭션 요청 : 클라이언트는 NewPooledTransactionHashes 메시지를 수신하면, 로컬 풀에 없는 트랜잭션 해시를 필터링하여 수집합니다. 그런 다음 GetPooledTransactions 메시지를 사용하여 해당 트랜잭션을 요청할 수 있습니다.
  • 트랜잭션 전파 : 클라이언트의 풀에 새로운 트랜잭션이 나타나면, Transactions 및 NewPooledTransactionHashes 메시지를 통해 네트워크에 전파합니다. Transactions 메시지는 완전한 트랜잭션 객체를 소수의 무작위 피어에게 전송하며, 나머지 피어는 트랜잭션 해시만 수신하고 필요 시 전체 트랜잭션 객체를 요청할 수 있습니다. 이를 통해 모든 노드가 트랜잭션을 수신하고, 추가 요청 없이 처리할 수 있도록 보장합니다.
  • 중복 전송 방지 : 노드는 이미 해당 트랜잭션을 알고 있는 피어에게 다시 트랜잭션을 보내지 않아야 합니다. 이를 위해 각 피어가 최근에 중계한 트랜잭션 해시를 기억하는 방식으로 중복 전송을 방지합니다.

Transaction Encoding and Validity


  • 피어 간에 교환되는 트랜잭션 객체는 두 가지 인코딩 중 하나를 가집니다. 우리는 이 두 가지 인코딩의 트랜잭션을 txₙ이라는 식별자로 참조합니다.
    • tx = {legacy-tx, typed-tx}
  • 유형이 지정되지 않은 레거시 트랜잭션은 RLP 목록으로 제공됩니다.
legacy-tx = [
    nonce: P,
    gas-price: P,
    gas-limit: P,
    recipient: {B_0, B_20},
    value: P,
    data: B,
    V: P,
    R: P,
    S: P,
]
  • EIP-2718형식의 트랜잭션은 RLP 바이트 배열로 인코딩되며, 첫 번째 바이트는 트랜잭션 유형(tx-type)이고 나머지 바이트는 유형별로 특정한 데이터(tx-data)입니다.
    • typed-tx = tx-type || tx-data

트랜잭션은 수신될 때 반드시 유효성을 검사해야 합니다. 유효성은 이더리움 체인 상태에 따라 달라집니다. 이 명세서에서 다루는 유효성의 특정 종류는 트랜잭션이 EVM에 의해 성공적으로 실행될 수 있는지 여부가 아니라, 로컬 풀에 임시 저장되고 다른 피어와 교환되는 것이 허용되는지 여부입니다.

트랜잭션은 아래 규칙에 따라 유효성을 검사합니다. 형식이 지정된 트랜잭션의 인코딩은 불투명하지만, 이들은 nonce, gas-price, gas-limit 값을 제공하며 트랜잭션의 서명에서 보낸 사람 계정을 확인할 수 있다고 가정합니다.

  • 트랜잭션이 형식화된 경우, tx-type은 구현체에 알려져 있어야 합니다. 정의된 트랜잭션 유형은 블록에 포함되기 전에 유효한 것으로 간주될 수 있습니다. 알 수 없는 유형의 트랜잭션을 전송하는 피어와는 연결을 끊어야 합니다.
  • 서명은 체인이 지원하는 서명 스키마에 따라 유효해야 합니다. 형식화된 트랜잭션의 경우, 서명 처리는 해당 유형을 소개하는 EIP에 정의되어 있습니다. 레거시 트랜잭션의 경우, 활성화된 두 가지 스키마는 기본 Homestead 스키마와 EIP-155 스키마입니다.
  • gas-limit는 트랜잭션의 '고유 가스(intrinsic gas)'를 충족해야 합니다.
  • 서명에서 파생된 트랜잭션의 보낸 사람 계정은 트랜잭션 비용(gas-limit * gas-price + value)을 충당할 수 있는 충분한 이더 잔액을 가져야 합니다.
  • 트랜잭션의 nonce는 보낸 사람 계정의 현재 nonce와 같거나 커야 합니다.
  • 트랜잭션을 로컬 풀에 포함할지 고려할 때, 구현체는 현재 계정 nonce보다 큰 '미래' 트랜잭션이 얼마나 유효한지, 그리고 'nonce gap'이 얼마나 허용되는지 결정할 수 있습니다.

구현체는 트랜잭션에 대해 다른 유효성 검사 규칙을 강제할 수 있습니다. 예를 들어, 128 kB보다 큰 인코딩된 트랜잭션을 거부하는 것이 일반적인 관행입니다.

달리 명시되지 않는 한, 구현체는 유효하지 않은 트랜잭션을 보낸다고 해서 피어와의 연결을 끊어서는 안 되며, 대신 단순히 트랜잭션을 폐기해야 합니다. 이는 피어가 약간 다른 유효성 검사 규칙을 따르고 있을 수 있기 때문입니다.


정리

  1. 트랜잭션 종류: 트랜잭션은 레거시 트랜잭션(구형)과 EIP-2718 형식화된 트랜잭션(신형) 두 가지로 구분됩니다.
  2. 유효성 검사: 트랜잭션 수신 시, 이를 로컬 풀에 저장하거나 다른 피어와 교환할 수 있는지 여부를 판단하기 위해 유효성 검사를 수행합니다.
  3. 형식화된 트랜잭션: EIP-2718 형식의 트랜잭션은 첫 바이트가 트랜잭션 유형(tx-type), 나머지는 유형별 데이터(tx-data)로 구성됩니다.
  4. 검사 규칙:
    • 트랜잭션 유형(tx-type)은 구현체에 알려져 있어야 합니다.
    • 서명은 유효해야 하며, 체인에서 지원하는 서명 스키마를 따라야 합니다.
    • gas-limit는 트랜잭션의 고유 가스를 충족해야 합니다.
    • 보낸 사람 계정은 충분한 이더 잔액을 가져야 합니다.
    • nonce는 현재 계정 nonce와 같거나 커야 합니다.
    • 구현체는 추가적으로 '미래' 트랜잭션이나 nonce 갭을 허용할지 결정할 수 있습니다.
  5. 중복 전송 방지: 유효하지 않은 트랜잭션을 보냈다고 해서 피어와의 연결을 끊어서는 안 되며, 단순히 트랜잭션을 폐기해야 합니다. 이는 피어가 다른 유효성 검사 규칙을 따를 수 있기 때문입니다.

Block Encoding and Validity


이더리움 블록은 다음과 같이 인코딩됩니다.


block = [header, transactions, ommers]
transactions = [tx₁, tx₂, ...]
ommers = [header₁, header₂, ...]
withdrawals = [withdrawal₁, withdrawal₂, ...]
header = [
    parent-hash: B_32,
    ommers-hash: B_32,
    coinbase: B_20,
    state-root: B_32,
    txs-root: B_32,
    receipts-root: B_32,
    bloom: B_256,
    difficulty: P,
    number: P,
    gas-limit: P,
    gas-used: P,
    time: P,
    extradata: B,
    mix-digest: B_32,
    block-nonce: B_8,
    basefee-per-gas: P,
    withdrawals-root: B_32,
]

특정 프로토콜 메시지에서는 트랜잭션 목록과 ommer 목록이 ‘block body'라는 단일 항목으로 함께 전달됩니다.


block-body = [transactions, ommers, withdrawals]

블록 헤더의 유효성은 사용되는 상황에 따라 달라집니다. 단일 블록 헤더의 경우 작업 증명(PoW) 봉인(mix-digest, block-nonce)의 유효성만 확인할 수 있습니다. 클라이언트의 로컬 체인을 확장하기 위해 헤더가 사용되거나 체인 동기화 중에 여러 헤더가 순차적으로 처리되는 경우 다음 규칙이 적용됩니다.


  • 헤더는 블록 번호가 연속적이며 각 헤더의 부모 해시(parent-hash)가 이전 헤더의 해시와 일치하는 체인을 형성해야 합니다.
  • 로컬에 저장된 체인을 확장할 때, 구현체는 Yellow Paper에 명시된 프로토콜 규칙에 따라 난이도, 가스 한도, 시간 값이 적절한지 확인해야 합니다.
  • gas-used 헤더 필드는 gas-limit보다 작거나 같아야 합니다.
  • 런던 하드포크 이후의 블록에서는 basefee-per-gas가 헤더에 있어야 하며, 이전 블록에서는 없어야 합니다. 이 규칙은 EIP-1559에 의해 추가되었습니다.
  • 병합(The Merge) 이후의 PoS 블록에서는 ommers 헤더가 존재할 수 없으므로 ommers-hash는 빈 keccak256 해시여야 합니다.
  • 상하이 포크 이후의 블록에서는 withdrawals-root가 헤더에 있어야 하며, 포크 이전의 블록에서는 없어야 합니다. 이 규칙은 EIP-4895에 의해 추가되었습니다.

완전한 블록의 경우, 블록의 EVM 상태 전환의 유효성과 블록의 (약한) '데이터 유효성'을 구별합니다. 상태 전이 규칙의 정의는 이 사양에서 다루지 않습니다. 즉각적인 block propagation와 state synchronization을 위해 블록의 데이터 유효성이 필요합니다.


블록의 데이터 유효성을 판단하기 위해 다음 규칙을 사용합니다. 구현체는 유효하지 않은 블록을 보내는 피어와의 연결을 끊어야 합니다.


  • 블록 header는 유효해야 합니다.
  • 블록에 포함된 transaction은 해당 블록 번호에서 체인에 포함될 수 있도록 유효해야 합니다. 즉, 앞서 언급된 트랜잭션 유효성 검사 규칙 외에도, 해당 블록 번호에서 트랜잭션 유형(tx-type)이 허용되는지 여부와 트랜잭션 가스 유효성을 블록 번호에 맞게 확인해야 합니다.
  • 모든 트랜잭션의 gas-limits 합이 블록의 gas-limit을 초과해서는 안 됩니다.
  • 블록의 transaction의 트랜잭션 목록의 머클 트리 해시를 계산하고 txs-root와 비교하여 검증해야 합니다.
  • 블록 본문의 인출 목록은 머클 트리 해시를 계산하고 withdrawals-root와 비교하여 검증해야 합니다. 인출은 합의 레이어에서 블록에 삽입되므로 추가적인 검증은 불가능합니다.
  • ommers 목록에는 최대 두 개의 헤더가 포함될 수 있습니다.
  • keccak256(ommers)는 블록 헤더의 ommers-hash와 일치해야 합니다.
  • ommers 목록에 포함된 헤더는 유효한 헤더여야 합니다. 이들의 블록 번호는 포함된 블록의 번호보다 크지 않아야 합니다. ommer 헤더의 부모 해시는 포함된 블록의 조상 중 깊이가 7 이하인 블록을 참조해야 하며, 이 조상 집합에 포함된 이전 블록에 포함된 적이 없어야 합니다.

Receipt Encoding and Validity


receipts는 블록의 EVM 상태 전이 결과입니다. 트랜잭션과 마찬가지로 영수증에는 두 가지 인코딩 방식이 있으며, 우리는 이 두 가지 인코딩을 receiptₙ이라는 식별자로 참조합니다.


receipt = {legacy-receipt, typed-receipt}

유형이 지정되지 않은 기존 영수증은 다음과 같이 인코딩됩니다.

legacy-receipt = [
    post-state-or-status: {B_32, {0, 1}},
    cumulative-gas: P,
    bloom: B_256,
    logs: [log₁, log₂, ...]
]
log = [
    contract-address: B_20,
    topics: [topic₁: B, topic₂: B, ...],
    data: B
]

EIP-2718 유형의 영수증은 RLP 바이트 배열로 인코딩됩니다. 여기서 첫 번째 바이트는 영수증 유형(tx-type과 일치)을 제공하고 나머지 바이트는 해당 유형과 관련된 불투명 데이터입니다.


typed-receipt = tx-type || receipt-data

Ethereum Wire Protocol에서 receipts은 항상 블록에 포함된 모든 receipts의 전체 목록으로 전송됩니다. 또한 영수증이 포함된 블록이 유효하고 알려져 있다고 가정합니다. 피어가 블록 receipts 목록을 수신하면 목록의 머클 트리 해시를 계산하고 블록의 receipts 루트와 비교하여 확인해야 합니다. 유효한 receipts 목록은 EVM 상태 전환에 의해 결정되므로 본 사양에서는 receipts에 대한 추가 유효성 규칙을 정의할 필요가 없습니다.


Protocol Messages


이더리움의 eth 프로토콜 메시지는 주로 네트워크 내에서 피어 간의 정보 교환을 위해 사용되며, 각 메시지는 특정 형식과 규칙을 따릅니다. 아래는 주요 메시지와 그 기능에 대한 설명입니다.


  • 요청 ID: 대부분의 메시지에서 첫 번째 요소는 request-id로, 요청하는 피어가 선택한 64비트 정수 값입니다. 응답하는 피어는 이 값을 그대로 응답 메시지에 반영해야 합니다.
  • 소프트 한계: 여러 메시지에서 소프트 한계가 설정되어 있으며, 예를 들어 BlockHeaders, BlockBodies, Receipts 응답은 2 MiB로 권장됩니다.
  • Status (0x00)
    • [version: P, networkid: P, td: P, blockhash: B_32, genesis: B_32, forkid]
    • 기능: 연결이 설정된 직후 피어의 현재 상태를 알립니다. 이는 다른 eth 프로토콜 메시지를 보내기 전에 수행되어야 합니다.
    • 구성 요소:
      • version: 현재 프로토콜 버전.
      • networkid: 블록체인을 식별하는 정수 값.
      • td: 최고 체인의 총 난이도.
      • blockhash: 최고(TD가 가장 높은) 블록의 해시.
      • genesis: 제네시스 블록의 해시.
      • forkid: EIP-2124 포크 식별자.
    • 아래는 일반적인 네트워크 ID와 해당 네트워크가 나열되어 있습니다.
    • 트랜잭션 replay prevention에 사용되는 EIP-155 체인 ID와 일치할 수도 있고, 아닐 수도 있기에 클라이언트는 특정 네트워크 ID를 사용할것을 요구하면 안된다.ID chain
      0 Olympic (disused)
      1 Frontier (now mainnet)
      2 Morden testnet (disused)
      3 Ropsten testnet (disused)
      4 Rinkeby testnet (disused)
      5 Goerli testnet
    • chain 정보들 : https://chainid.network/
  • NewBlockHashes (0x01)
    • [[blockhash₁: B_32, number₁: P], [blockhash₂: B_32, number₂: P], ...]
    • 기능: 네트워크에 새로 나타난 블록을 피어에게 알립니다. 피어가 알지 못할 가능성이 있는 모든 블록을 포함해야 하지만, 이미 알리고 있는 해시를 중복하여 보내는 것은 피어의 평판을 떨어뜨릴 수 있습니다.
    • 나중에 보내는 노드가 진행 중인 GetBlockHeaders 메시지에 따르기를 거부하는 해시를 포함하는 것은 잘못된 형식으로 간주되어 보내는 노드의 평판을 낮출 수 있습니다.
  • Transactions (0x02)
    • [tx₁, tx₂, ...]
    • 기능: 피어가 트랜잭션 큐에 포함시켜야 할 트랜잭션을 지정합니다. 이 메시지는 최소 하나의 새로운 트랜잭션을 포함해야 하며, 동일한 트랜잭션을 같은 세션에서 재전송하지 않아야 합니다.
    • 트랜잭션 메세지에는 하나 이상의 새로운 트랜잭션이 포함되어야 한다.
      • 빈 트랜잭션 메세지는 권장되지 않으며, 연결이 끊어질 수 있다.
    • 재전송된 트랜잭션을 받은 피어에게 중계해서는 안된다.
      • 실제로 이는 이미 전송되거나 수신된 피어 별 볼륨 필터 또는 트랜잭션 해시 세트를 유지하여 구현하는 경우가 많다.
  • GetBlockHeaders (0x03) / BlockHeaders (0x04)
    • GetBlockHeaders (0x03) : [request-id: P, [startblock: {P, B_32}, limit: P, skip: P, reverse: {0, 1}]]
    • BlockHeaders (0x04) : [request-id: P, [header₁, header₂, ...]]
    • 기능: 블록 헤더 요청과 그에 대한 응답 메시지입니다. 요청 시, 시작 블록, 한계, 스킵, 역순 등을 지정하여 블록 헤더 목록을 요청할 수 있습니다.
    • 응답: 요청된 헤더 목록을 포함하며, 요청된 블록 헤더를 찾지 못한 경우 목록이 비어 있을 수 있습니다.
  • GetBlockBodies (0x05) / BlockBodies (0x06)
    • GetBlockBodies (0x05) : [request-id: P, [blockhash₁: B_32, blockhash₂: B_32, ...]]
    • BlockBodies (0x06) : [request-id: P, [block-body₁, block-body₂, ...]]
    • 기능: 블록 본문 데이터 요청과 그에 대한 응답 메시지입니다. 요청된 블록의 본문 데이터를 포함하며, 요청된 블록을 찾지 못한 경우 목록이 비어 있을 수 있습니다.
  • NewBlock (0x07)
    • [block, td: P]
    • 기능: 피어가 알아야 할 하나의 완전한 블록을 지정합니다. td는 해당 블록의 총 난이도입니다.
  • NewPooledTransactionHashes (0x08)
    • [txtypes: B, [txsize₁: P, txsize₂: P, ...], [txhash₁: B_32, txhash₂: B_32, ...]]
    • 기능: 네트워크에 나타난, 아직 블록에 포함되지 않은 트랜잭션을 알리는 메시지입니다. 트랜잭션 유형, 크기, 해시 목록이 포함됩니다.
    • 특징: 트랜잭션 해시와 크기를 통해 피어에게 트랜잭션을 알립니다.
  • GetPooledTransactions (0x09)
    • [request-id: P, [txhash₁: B_32, txhash₂: B_32, ...]]
    • GetPooledTransactions 요청에 권장되는 소프트 제한은 256개 해시(8KiB)입니다.
    • 수신자는 응답(크기 또는 제공 시간)에 대해 임의의 제한을 적용할 수 있으며 이는 프로토콜 위반으로 간주되어서는 안 됩니다.
  • PooledTransactions (0x0a)
    • [request-id: P, [tx₁, tx₂...]]
    • 이는 로컬 풀에서 요청된 트랜잭션을 반환하는 GetPooledTransactions에 대한 응답입니다.
    • 트랜잭션은 요청과 동일한 순서여야 하지만 사용할 수 없는 트랜잭션을 건너뛰어도 괜찮습니다.
    • 이때 응답 크기 제한에 도달한 경우 요청자는 다시 요청할 해시(마지막 반환된 트랜잭션에서 시작하는 모든 것)와 사용할 수 없다고 가정할 해시(마지막 반환된 트랜잭션 전의 모든 간격)를 알게 됩니다.
    • NewPooledTransactionHashes를 통해 거래를 알리고, PooledTransactions를 통해 거래 제공을 거부하는것이 허용되는데 이러한 상황은 INFO와 REQUEST 사이에 트랜잭션이 블록에 포함되고, 풀에서 제거될 때 발생할 수 있다.
    • 풀의 트랜잭션과 일치하는 해시가 없으면 피어는 빈 목록으로 응답할 수 있습니다.
  • GetReceipts (0x0f)
    • [request-id: P, [blockhash₁: B_32, blockhash₂: B_32, ...]
    • 피어가 지정된 블록 해시의 영수증이 포함된 영수증 메세지를 반환하도록 요구합니다.
    • 단일 메세지에서 요청할 수 있는 확인 수는 구현에 정의된 제한에 따라 달라질 수 있습니다.
  • Receipts (0x10)
    • [request-id: P, [[receipt₁, receipt₂], ...]]
    • 요청된 블록 영수증을 제공하는 GetReceipts에 대한 응답입니다.
    • 응답 목록의 각 요소는 GetReceipts 요청의 블록 해시에 해당하며 블록 영수증의 전체 목록을 포함해야 합니다.
    • 영수증 응답에 권장되는 소프트 제한은 2MiB입니다.

CTF를 운영하게 되면서 간단한 블록체인 문제를 만들어봤다.

공개되어 있는 Zellic의 Template이나 ChainFlag의 Template을 사용하여 만들다가 한 번 구현해볼까?라는 생각으로 어쩌다 만들게 되었다. geth를 이용해 만들다가 결국 Ganache로 결정되었다.

 

https://github.com/KindKillerwhale/Blockchain-CTF-Template

 

GitHub - KindKillerwhale/Blockchain-CTF-Template: Blockchain-CTF-Template

Blockchain-CTF-Template. Contribute to KindKillerwhale/Blockchain-CTF-Template development by creating an account on GitHub.

github.com

 

급하게 구현한다고 코드가 깔끔하고 효율적이지는 않다. 전체적으로 고칠 점이 많다. 대회 운영을 위해 기능 구현만 해보았다. 나중에 차근차근 고쳐봐야겠다.

영상에 정리된 내용을 번역한 내용


비트코인과 블록체인


블록체인 기술을 활용한 첫 번째 프로토콜 중 하나인 비트코인에 대해 잘 알고 있을 것이다. 사토시 나카모토(가명)가 작성한 비트코인 백서에서는 비트코인이 암호화를 사용하여 탈중앙화된 네트워크 내에서 P2P 거래를 촉진할 수 있는 방법을 설명했다. 이는 검열 저항 금융(censorship-resistant finance)을 탄생시켰다. 비트코인은 금과 유사하게 고정된 양이 있다. 이에 대한 자세한 내용은 비트코인 백서에서 확인할 수 있다.


이더리움과 스마트 계약


비트코인이 탄생한 몇 년 후, 비탈릭 부테린은 블록체인 인프라를 기반으로 추가 기능을 갖춘 이더리움을 설립했다. 이더리움을 통해 중앙 중개인 없이 탈중앙화된 거래, 조직, 계약을 생성할 수 있다. 이는 스마트 계약의 추가를 통해 가능해졌다. 스마트 계약의 개념은 원래 닉 사보에 의해 1994년에 구상되었지만, 이더리움이 이를 현실화했다.

스마트 계약은 중앙화되거나 제3자 중개인 없이 탈중앙화된 방식으로 실행되는 명령어 집합이다. 비트코인에도 스마트 계약 기능이 있지만, 의도적으로 튜링 불완전하게 되어 있다.


비트코인과 이더리움의 비교


비트코인은 탈중앙화된 디지털 화폐의 개념을 도입했다. 비트코인은 가치 저장 수단으로 기능하며, 중앙 권위 없이 P2P 거래를 가능하게 한다. 이러한 탈중앙화는 어떤 단일 주체도 네트워크를 통제하지 않게 하여 비트코인을 검열 저항적이고 중앙 집중화된 실패 지점에 취약하지 않게 만든다.


이더리움은 비트코인의 기술을 확장하여 스마트 계약을 도입했다. 스마트 계약은 모든 조건과 약관이 코드에 투명하게 작성된 자동 실행 계약이다. 이러한 계약은 신뢰를 최소화한 합의이며, 중개자의 필요성을 제거한다. 이더리움의 플랫폼은 탈중앙화 애플리케이션(dApp)의 생성을 가능하게 하며, 블록체인과 탈중앙화된 네트워크를 통해 현실 세계 데이터와 상호 작용할 수 있다.


오라클 문제


스마트 계약은 현실 세계의 데이터와 상호 작용하거나 접근할 수 없다는 중요한 한계에 직면해 있다. 이를 오라클 문제라고 한다. 블록체인은 결정론적 시스템이기 때문에 모든 일이 그들의 생태계 내에서 발생한다. 스마트 계약을 더 유용하게 하고 현실 세계의 데이터를 처리할 수 있도록 하기 위해서는 외부 데이터와 연산이 필요하다. 오라클은 이 목적을 수행한다. 오라클은 블록체인에 데이터를 제공하거나 외부 연산을 실행하는 장치 또는 서비스다. 탈중앙화를 유지하려면 단일 소스에 의존하지 않고 탈중앙화된 오라클 네트워크를 사용하는 것이 필요하다. 이와 같은 온체인 논리와 오프체인 데이터를 결합하면 하이브리드 스마트 계약이 탄생한다.


체인링크


체인링크는 스마트 계약이 외부 데이터와 연산에 접근할 수 있도록 하는 인기 있는 탈중앙화 오라클 네트워크다. 체인링크는 블록체인에 구애받지 않기 때문에 모든 체인에서 작동한다.


주요 기능 및 이점


  • 탈중앙화: 스마트 계약은 노드에 의해 유지되는 탈중앙화된 네트워크에서 작동하며, 중앙 중개자의 필요성을 제거한다.
  • 투명성과 유연성: 블록체인에서 모든 거래와 계약 실행은 모든 사람에게 공개되어 투명성과 공정성을 보장한다. 또한, 계정이 실제 신원과 연결되지 않아 프라이버시가 유지된다.
  • 속도와 효율성: 블록체인 거래는 즉각적으로 이루어지며, 며칠 또는 몇 주가 걸리는 전통적인 은행 송금과 다르다. 이 효율성은 금융 결제에도 적용되어 청산소의 필요성을 제거하고 결제 시간을 단축시킨다.
  • 보안성과 불변성: 스마트 계약이 배포되면 변경할 수 없어 조건이 변하지 않음을 보장한다. 블록체인을 해킹하는 것은 탈중앙화된 특성 때문에 매우 어렵기 때문에 중앙 집중식 시스템보다 정보를 보호하는 더 안전한 방법을 제공한다.
  • 상대방 위험 감소: 스마트 계약은 중개자에 대한 신뢰의 필요성을 제거하여 인간의 개입이나 사기 없이 코드로 작성된 대로 계약이 실행되도록 보장한다.

 


레이어 2 확장 솔루션


블록체인이 성장함에 따라 확장 문제에 직면하게 된다. 이를 해결하기 위해 레이어 2(L2) 솔루션이 개발되었다. L2 솔루션은 다른 블록체인이 메인 블록체인에 연결되도록 하여 기본적으로 확장할 수 있도록 한다. L2 솔루션에는 두 가지 주요 유형이 있다:


  • Optimistic Rollups: eg. Optimism, Arbitrum
  • Zero-Knowledge Rollups: eg. ZK Sync, Polygon ZK EVM

 


일반 용어


 

웹3


웹3는 블록체인과 스마트 계약으로 구동되는 인터넷의 새로운 패러다임을 설명하는 데 사용되는 용어다. 웹의 이전 버전과 달리 웹3는 허가가 필요 없으며 중앙 서버가 아닌 탈중앙화된 네트워크에 의존한다. 이는 검열 저항적이고 투명한 계약 및 거래의 시대를 열어 소유 경제라고도 불린다.


  • 웹1: 정적 콘텐츠가 있는 무허가 오픈 소스 웹
  • 웹2: 기업이 서버에서 여러분의 계약을 실행하는 동적 콘텐츠가 있는 허가된 웹
  • 웹3: 동적 콘텐츠가 있는 무허가 웹

 

탈중앙화된 검열 저항 네트워크가 여러분의 계약과 코드를 실행한다. 사용자 소유 생태계에서는 사용자가 상호작용하는 프로토콜의 일부를 소유한다. 단순히 제품일 뿐인 것과는 다르다.


블록체인과 스마트 계약의 본질


우리 삶에서 거의 모든 상호작용이나 거래는 어떤 형태의 계약 또는 합의와 관련이 있다. 예를 들어, 의자를 구매하는 것은 목재를 사서 조립하고 완성된 제품을 판매하기 위한 계약을 포함한다. 전기 공급도 전력 회사와의 계약에 기반한다. 자동차 오일 교환 시에도 서비스에 대한 대가로 돈을 지불하는 계약이 존재한다. 현대 생활의 거의 모든 것은 어떤 형태로든 계약이나 합의와 관련이 있다.


전통적인 합의의 문제


신뢰에 기반한 계약이 잘못될 수 있는 실제 예를 살펴보고, 블록체인 기술과 스마트 계약이 이러한 위험을 어떻게 완화하는지 알아보겠다.


소비자 신뢰


1980년대와 1990년대에 맥도날드의 모노폴리 게임은 고객에게 구매 시 얻는 게임 카드를 통해 돈을 받을 기회를 약속했다. 그러나 이 게임은 내부 관계자들이 시스템을 조작하여 자신들의 이익을 위해 조작한 것으로 드러났다. 즉, 맥도날드는 고객과의 약속을 지키지 못했다. 이 예시는 계약 내에서 신뢰에 의존하는 것이 사기 활동과 약속 파기로 이어질 수 있음을 보여준다.


스마트 계약을 통해 우리는 신뢰의 필요성을 제거할 수 있다. 스마트 계약은 탈중앙화된 블록체인에 배포되는 계약 또는 명령어 집합이다. 한 번 배포되면 변경할 수 없으며 자동으로 실행되고 모든 사람이 그 조건을 볼 수 있다. 맥도날드의 모노폴리 게임이 블록체인 스마트 계약을 통해 운영되었다면, 스마트 계약의 불변적, 탈중앙화, 투명한 특성으로 인해 사기 행위는 불가능했을 것이다.


은행과 신뢰


전통적인 은행은 때때로 사람들의 돈을 안전하게 보호하겠다는 약속을 지키지 못했으며, 이는 대공황 때 두드러졌다. 블록체인과 스마트 계약은 투명성을 보장하고 자동화된 지급 능력 검사를 실행하여 은행이 지급 불능 상태가 되는 것을 방지할 수 있다.


금융 시장 접근


전통적인 거래소와 같은 중앙 기관은 금융 시장에 대한 접근을 제한할 수 있는 권한을 가지고 있다. 이는 2021년에 로빈후드가 특정 자산에 대한 거래를 제한했을 때 명백하게 드러났다. 유니스왑과 같은 탈중앙화 거래소에서는 중앙 권한이 시장 접근을 변경하거나 제한할 수 없다. 이는 금융 시장에 공정성과 개방성을 도입한다.


스마트 계약은 신뢰 기반 시스템에 대한 의존을 최소화하여 과거에 반복적으로 실패했던 문제들을 해결한다.


스마트 계약의 기능


스마트 계약은 비교적 새로운 기술이지만 이미 다양한 시장을 변화시키기 시작했다. 스마트 계약은 블록체인에 '약속'을 코드로 나타낸다. 이 코드는 탈중앙화된 집단에 의해 실행되며, 단일 엔터티가 계약을 변경할 수 없게 한다. 계약과 그 조건은 공공 지식이 되며, 인간의 개입 없이 자동으로 실행된다. 더 많은 산업이 스마트 계약과 블록체인을 채택하고 있으며, 이는 신뢰 최소화된 계약 또는 깨지지 않는 약속으로 간단히 표현할 수 있다.


주의 사항


그러나 탈중앙화된 것처럼 보이지만 실제로는 그렇지 않은 플랫폼을 주의해야 한다. 2022년의 SBF의 FTX 플랫폼이 그 예다. FTX는 자신을 웹3 플랫폼으로 소개했지만 실제로는 스마트 계약의 이점을 누리지 못한 전통적인 웹2 회사였다.


 

 

+ Recent posts