September 10, 2026

Merkle Tree and Ethereum Objects — Ethereum Yellow Paper Walkthrough (2/7)(ko)

Merkle Tree and Ethereum Objects — Ethereum Yellow Paper Walkthrough (2/7)(ko)

https://www.lucassaldanha.com/ethereum-yellow-paper-walkthrough-2/

(출처)

원글 저자의 허락을 맡았습니다.

처음하는 번역이라 표현이나 글에 대해서 어색하거나 이상한 부분이 다수 있을겁니다. 많은 태클 부탁드립니다!

(그래서 영어를 잘하신다면 원문을 읽으시는게 ㅎㅎ….)

모든 용어에 대해서 번역은 하지않았고 원래 단어로 가는게 더 이상적일거 같은것은 그대로 유지하였습니다( ex. transaction=> 트랜잭션 )

안녕! 여러분!

이 글은 이더리움 Yellow paper를 알아보는 두번쨰 글입니다.

이 글에서 우리는 이더리움의 메인 객체와 그들의 역할을 배워볼것입니다.

그리고 어떻게 머클 트리가 이더리움에 쓰이는지 간략하게 알아보겠습니다.

이 글을 읽은다음에 머클트리가 이더리움에서의 역할, world state가 뭔지, account state가 뭔지 그리고 트랜잭션과 블록이 뭔지에 대해서 알기를 바랍니다.

만약 이더리움과 블록체인 패러다임에 대해서 얘기한 이전글을 안읽었으면

읽고오는것을 추천합니다.

이더리움의 메인 데이터 객체에 대해서 얘기하기 전에 Merkle Tree가 뭔지와 그걸 유용하게 만드는 속성에 대해서 말하고 싶습니다.

Yellow paper에서는

Yellow paper에서는 Merkle Patricia tree에서 world state와 트랜잭션을 유지하고 있다고 가정합니다.

이 데이터 구조는 부록 D에 설명되어 있습니다.

Merkle Patricia tree에는 정말 흥미로운 속성이 있으며 이더리움 구현에 대해서 더 배우고 싶다면 이 기사를 읽는것을 추천합니다.

( article : https://github.com/ethereum/wiki/wiki/Patricia-Tree)

Merkle Tree에서 리프노드에는 데이터 블록의 해시가 포함되고 리프 노드가 아닌곳 에서는 자식 노드의 해시가 포함됩니다.

(Image from: https://en.wikipedia.org/wiki/Merkle_tree)

Merkle Tree에서 하위의 데이터를 수정하면 해당 데이터를 참조하는 노드의 해시가 변경됩니다.

각각의 부모 노드 해시는 자식의 데이터에 의존하기 때문에 자식노드의 데이터가 변경되면 부모 노드의 해시도 변경됩니다. 이런 일은 각 상위노드로 하여 루트노드까지 발생합니다.

그러므로 리프노드의 데이터의 변경은 루트 노드의 해시의 변경시킬수 있습니다.

여기서 우리는 두가지 중요한 속성을 도출해낼수 있습니다.

  1. 우리는 모두 같은 데이터를 가졌는지 확인하려고 모든 리프노드를 비교할 필요가 없습니다. 우리는 단지 루트노드의 해시만 비교하면 되기 때문입니다.
  2. 만약 특정 데이터가 트리의 부분임을 증명하려면 Merkle proofs라고 불리는 기술을 쓸수있습니다. 데이터가 트리에 있는지를 확인하는 쉽고 효과적인 기술이지만 여기서는 다루지않을겁니다.

(Merkle proofs : https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5)

첫번째 속성은 해당 시점에 데이터를 나타내는 루트노드의 해시만 저장할 수 있도록 하기 때문에 중요합니다. 즉 블록체인에 모든 데이터를 저장하는 것과 반대로 블록을 나타내는 트리의 루트 해시만 저장하고 데이터는 변경할 수 없는 상태를 유지하면 됩니다.

이제 우리는 Merkle Tree 루트 해시가 무엇을 의미하는지 알았습니다.

이제 이더리움 주요 객체에 대해서 얘기합시다!

World state는 주소(계정)과 상태간의 매핑입니다. World state는 블록체인에 저장되지는 않지만

Yellow paper에서는 이 데이터를 트리( state database 혹은 state trie라고 불리는) 에 저장할 것으로 예상됩니다. World state는 트랜잭션 실행으로 인한 지속적으로 업데이트 되는 글로벌 상태라고 볼수 있습니다. 이더리움 네트워크가 분산형 컴퓨터와 같다는 내용이 있는 첫번째 게시물에서의 설명을 기억한다면 World state는 이 컴퓨터의 하드드라이브로 간주됩니다.

모든 이더리움 계정에 대한 정보는 world state에 있고 world state trie에 저장됩니다.

만약 너가 계정의 잔액을 알고싶다거나 스마트 컨트랙트의 현재 상태를 알고싶으면 너는 world state tire에 쿼리 하여서 해당 계정의 계정상태를 받을수가 있다. 이 데이터가 어떻게 저장되는지 곧 설명하겠습니다.

이더리움에서는 두가지 유형의 계정이 있습니다. External Owned Accounts(EOA)와 Contract Account입니다. EOA계정은 이더를 서로 보내고 스마트 컨트랙트를 배포하는데 사용할 수 있는 우리가 가질수 있는 계정입니다. Contract Account는 스마트 컨트랙트가 배포될때 생성되는 계정입니다.

모든 스마트 컨트랙트는 자신의 이더리움 계정을 가지고 있습니다.

Account State에는 이더리움 계정에 대한 정보가 포함되어 있습니다.

예를 들어 , 계정이 얼마나 이더를 가지고 있는지와 발송된 트랜잭션 수를 저장합니다. 각 계정은 Account state를 가지고 있습니다.

Account State의 각 필드를 보겠습니다.

nonce

  • 만약 계정이 EOA라면 발송된 트랜잭션의 수이고 또는 이 계정에서 생성된 컨트랙트의 수이다. (지금은 계약 생성에 대해서 신경쓰지 마세요.)

balance

  • 이 계정이 소유한 총 이더(Wei)입니다.

storageRoot

  • account storage trie의 루트노드 해시

codeHash

  • Contract Account라면 이 계정의 EVM코드의 해시입니다. EOA일떄는 비어있게 됩니다.

Account state에 대한 한가지 중요한 세부 정보는 CodeHash를 제외한 모든 필드를 변경할수 있다는것입니다. 예를 들어 한 계정에서 다른 계정으로 이더를 보내면 nonce는 증가하고 balance는 새로운 balance를 반영하여 업데이트 됩니다.

CodeHash가 변경 불가능하기떄문에 만약 너가 버그가 있는 컨트랙트를 배포하면 넌 그걸 업데이트 할수없고 새로운 버전을 배포해야된다.( 버기 버전은 영구적이다.). 이러한 이유 때문에 Truffle을 사용해서 컨트랙트를 개발하고 테스트하거나 솔리디티의 작업시 모범 사례를 따라야되는것이다.

Account Storage Trie는 계정과 관련된 데이터가 저장된 위치입니다. 이건 Contract Account에만 해당됩니다. EOA는 storageRoot와 CodeHash가 비어있습니다. 모든 스마트 컨트랙트 데이터는 32바이트 정수의 매핑으로 Account Storage Trie에 유지됩니다. 어떻게 Account Storage Trie에 유지되는지에 대해서 자세히는 얘기하지 않겠습니다. 만약 이 내부구조에 대해서 자세히 알고싶다면 이 글을 읽어보는걸 추천합니다. account storage 루트 노드의 해시는 각 계정 Account state의 storageRoot 필드에 저장됩니다.

( Account Storage Trie : https://medium.com/coinmonks/a-practical-walkthrough-smart-contract-storage-d3383360ea1b)

지난 글을 읽어보면 트랜잭션이 현재 상태에서 다음 상태로 변화하는 원인이라는것을 기억할겁니다.

이더리움에는 3가지 타입의 트랜잭션이 있습니다.

  1. 두 EOA사이에 값을 전송하는 트랜잭션( 예: 발신자,수신자 둘다 계정 잔액 변경)
  2. 컨트랙트에게 메시지 호출을 하는 트랜잭션( 예: 설정 함수를 실행시키는 메시지 호출로 스마트 컨트랙트의 값 설정)
  3. 컨트랙트를 배포하는 트랜잭션(따라서, Contract Account)

( 엄밀히 말하면, 타입 1과 2는 같습니다…EOA, Contract Account 각각 Account state에 영향을 미치는 메시지 호출입니다. 그러나 3가지로 생각하는게 더 쉽지않을까요?)

트랜잭션의 필드는 다음과 같습니다.

nonce

  • 트랜잭션을 생성한 계정에서 보낸 트랜잭션 수

gasPrice

  • 이 트랜잭션을 실행하기 위한 가스 단위당 지불될 값(wei 단위)

gasLimit

  • 이 트랜잭션을 실행하면서 사용될 최대 가스 양

to

  • 이더를 전송하는 트랜잭션이라면 전송받을 EOA 주소
  • 컨트랙트에 메시지를 보내는 트랜잭션이라면 컨트랙트의 주소
  • 컨트랙트를 생성하는 트랜잭션이라면 비어있다.

value

  • 이더를 전송하는 트랜잭션이라면 전송될 Wei 양이다.
  • 컨트랙트에 메시지를 보내는 트랜잭션이라면 스마트 컨트랙트에 의해 payable될 금액이다.
  • 컨트랙트를 생성하는 트랜잭션이라면 생성될 계좌의 잔액에 추가될 Wei이다.

(payable : https://medium.com/@rsripathi781/6-payable-functions-in-solidity-smartcontract-ethereum-d2535e346dc1)

v , r , s

  • 트랜잭션을 보낸 사람을 확인하는데 사용되는 트랜잭션의 암호화 서명에 사용되는 값이다.

data ( 스마트 컨트랙트에 value transfer 혹은 메시지를 보낼때만 해당)

  • 메시지 호출의 입력 데이터( 예 : 만약 너가 스마트 컨트랙트의 설정 함수를 실행시키려 한다면 데이터 필드에는 설정 함수의 식별자와 매개 변수로 전달될 값이 있어야한다.)

init( 컨트랙트 생성 전용)

  • 컨트랙트 초기 설정에 사용된 EVM코드

(Initialization of the contract : https://medium.com/@hayeah/diving-into-the-ethereum-vm-part-5-the-smart-contract-creation-process-cb7b6133b855)

이 모든걸 한번에 다 이해하려고 하지마세요. data 필드 나 init 필드의 의미와 어떻게 쓰이는지에 대해서 이해하려면 이더리움에 대해서 더 깊은 이해가 필요하다. 지금은 깊이 이해할 떄가 아닙니다.

당연하게도 블록의 모든 트랜잭션은 trie에 저장됩니다. 그리고 trie의 루트 해시는 블록헤더에 저장됩니다. 이제 이더리움 블록 구조에 대해서 알아보겠습니다.

블록 헤더는 블록 헤더, 블록 바디 두가지로 나뉘어 집니다.

블록 헤더는 이더리움의 블록 체인 부분입니다. 이전 블록(상위 블록이라고도 합니다.)의 해시를 포함하고 있으며 암호화 보장 체인을 구축하고있습니다.

블록 바디는 이 블록에 포함된 트랜잭션 목록과 엉클 블록 헤더 목록이 포함되어있습니다

( list of transaction : https://medium.com/blockchannel/life-cycle-of-an-ethereum-transaction-e5c66bae0f6e)

( uncle block : https://github.com/ethereum/wiki/wiki/Design-Rationale#uncle-incentivization)

블록 헤더의 모든 필드를 보겠습니다.

parentHash

  • 이전 블록의 블록 헤더 해시입니다. 체인의 첫번쨰 블록까지 각 블록에는 이전 블록의 해시를 포함하여 데이터 수정을 방지합니다.( 이전 블록을 수정하게 되면 수정된 블록 이후의 모든 블록의 해시가 변경됨)

ommersHsh

  • 엉클 블록 헤더의 해시는 블록바디에 포함되있습니다.

beneficiary

  • 이 블록을 채굴할떄의 수수료를 받을 이더리움 계정

stateRoot

  • World state trie의 루트노드 해시( 모든 트랜잭션이 실행된 후)

transactionsRoot

  • 트랜잭션 trie의 루트 노드 해시. 이 trie는 블록 바디의 모든 트랜잭션을 포함한다.

receiptsRoot

  • 트랜잭션이 실행될 떄마다 , 이더리움은 트랜잭션 실행에 대한 정보가 담긴 트랜잭션 영수증을 생성합니다. 이 필듣 트랜잭션 영수증 trie의 루트노드 해시입니다.

logsBloom

  • Bloom filter는 이 블록의 트랜잭션에서 로그가 생성되었는지 확인할때 사용됩니다.
  • 이렇게 하면 블록에 로그가 저장되지 않습니다.(공간절약)

( Bloom filter : https://hackernoon.com/probabilistic-data-structures-bloom-filter-5374112a7832)

( more information : https://ethereum.stackexchange.com/questions/3418/how-does-ethereum-make-use-of-bloom-filters/3426#3426)

difficulty

  • 이 블록의 난이도 입니다. 이 블록이 얼마나 채굴하기 어려운지를 알수있습니다.( 자세한 계산 과정은 적지않습니다.)

number

  • 상위 블록 수입니다. 이것은 체인의 높이를 나타냅니다(체인에 블록이 몇개 있는지)
  • 제네시스 블록은 0번입니다.

gasLimit

  • 각 거래는 가스를 소비합니다. gas limit는 블록에 포함된 트랜잭션에서 사용할 수 있는 최대 가스를 지정합니다. 이건 블록의 트랜잭션 수를 제한하는 방법입니다.

gasUsed

  • 블록에 있는 트랜잭션의 가스 비용을 더합니다.

timestamp

  • 블록이 생성되었을때 Unix 타임스탬프입니다. 이더리움의 분산화적 특성때문에 이 값을 신뢰할수는 없습니다( 특히 시간과 관련된 비즈니스 로직을 가진 스마트 컨트랙트를 구현할 때)

extraData

  • 모든 내용을 포함할 수있는 임의의 바이트 배열입니다. miner가 블록을 생성할 때, 이 필드에 뭐든지 추가할 수 있습니다.

mixHash

  • 해시는 블록이 올바르게 채굴되었는지 확인하는데 사용됩니다.

(이해하고 싶으시다면 https://github.com/ethereum/wiki/wiki/Ethash 를 읽어보세요)

nonce

  • mixHash와 같이 블록이 올바르게 채굴되었는지 확인할 떄 사용됩니다.

휴… 많은 내용이 있는데 천천히 읽어보시길 바랍니다.

여기서 중요한 것은 각각 필드와 필드의 내용을 기억하는게 아닙니다.(그떄마다 구글이 있음)

제가 의도한 것은 Yellow paper에 적혀있는것보다 쉽게 각 필드에 대한 이해를 해주려는 것입니다.

Think of it as an Ethereum objects for dummies! 🙂

지금까지 본것을 간단하게 요약해봅시다. 기본적으로 이더리움에는 4자기 유형의 트리가 있습니다.

  1. The World state trie는 계정과 account state의 매핑을 포함한다. The World state trie의 루트 노드의 해시는 블록에 포함되어(stateRoot 필드) 해당 블록이 생성되었을때 현재 상태를 나타냅니다. 우리는 오직 하나의 world state trie를 가집니다.
  2. The account storage trie는 스마트 컨트랙트와 관련된 데이터를 포함합니다. The Account state trie의 루트 노드 해시는 Account state( storageRoot필드) 에 포함되어있습니다. 각 계정마다 하나의 Account storage를 가집니다.
  3. 트랜잭션 트리는 블록의 모든 트랜잭션을 포함합니다. 트랜잭션 트리의 루트 노드 해시는 블록 헤더에 포함됩니다.( transactionRoot 필드) 블록당 하나의 트랜잭션 트리를 가집니다.
  4. 트랜잭션 receipt 트리는 블록에 포함된 모든 트랜잭션의 트랜잭션 receipt를 포함합니다. 트랜잭션 receipt 트리의 루트 노드 해시는 블록헤더에 포함됩니다(receiptsRoot 필드). 각 블록당 하나의 트랜잭션 receipt 트리가 있습니다.

오늘 우리가 본 object들은 다음과 같습니다.

  1. World state : 이더리움인 분산 컴퓨터의 하드드라이브. 주소와 account state의 매핑입니다.
  2. Account state : 이더리움 계정의 각 상태를 저장합니다. 또한 계정에 대한 storage data를 포함하는 account state의 storageRoot도 포함합니다.
  3. 트랜잭션 : 시스템에서의 상태 전환을 나타냅니다. 예를 들자면 자금이전, 메시지 호출, 컨트랙트 배포이다.
  4. 블록 : 이전 블록에 대한 링크(parentHash)와 실행되었을때 새로운 상태를 만드는 트랜잭션 그룹이 포함되어있습니다. 또한 stateRoot, transactionRoot, receiptsRoot와 world state trie, 트랜잭션 트리 , 트랜잭션 receipts 트리 각각의 루트 노드 해시가 포함되있습니다.

난 아래 그림은 이 포스팅에 관한 모든 정보를 캡쳐한것이다.

여러분이 이 글이 유용했다고 생각했으면 좋겠고, 앞서 말했듯이 주된 목적은 블록체인과 이더리움 생태계에 대해서 익숙하지 않은 사람들이 이해 할수 있도록 하는것이였다.

내가 느끼기에는 YellowPaper로 공부하는것은 굉장히 어렵고 많은 인내심이 필요하다.

이더리움 프로토콜에서 일하는것은 굉장히 흥미롭고 매일 새로운것을 배울 기회가 생긴다.

이 글에서 명확하지 않은 부분에 대해서 지적하시고 의견을 주시면 가능한 빨리 답변을 드리겠습니다. 프로토콜에 대해서 잘못된 인식을 퍼트리고 싶지는 않습니다.

다음 글에서는 이더리움이 왜 가스를 가지는지와 트랜잭션 실행 모델에 대해서 써보겠습니다.

다음에 봐요!

Published at Mon, 14 Oct 2019 17:35:20 +0000

{flickr|100|campaign}

Previous Article

US Treasury Secretary Says Firms Left Libra Due to Compliance Issues

Next Article

Bitcoin Core 0.18.0 Released