관리 메뉴

HAMA 블로그

[비트코인] 머클패스의 주체는 누구? 거래검증? 거래확정? 본문

블록체인

[비트코인] 머클패스의 주체는 누구? 거래검증? 거래확정?

[하마] 이승현 (wowlsh93@gmail.com) 2018. 3. 12. 15:22


* 이 글은 누군가를 이해 시키기 위한 글이 아닙니다. 블록체인을 처음 만난 개발자가 비트코인의 핵심이라 할 수 있는 거래(검증)에 대한 공부/삽질을 하며 겪는 여정으로써 굉장히 불친절한 글이라는 것을 말씀드립니다. 그냥 제 삽질일기~




그림 7-5에서는 단지 32바이트 크기의 해시 4개의 길이(총 128바이트)인 머클 경로를 생성함으로써 거래 K 가 블록 내에 포함되어 있다는 사실을 노드가 입증할 수 있다는 것을 보여준다. 머클패스는 HL .......(그림에서 파랑) 등등 이렇게 4개의 해시로 구성되어 있다. 인증 경로로 제공된 이 4개의 해시를 가지고 어떤 노드라도 4개의 해쉬에 대응하는 해시쌍인 H .... (그림에서 점선) 와 머클트리 루트를 계산함으로써 HK가 머클 루트에 포함되어 있다는 사실을 증명 할 수 있다.


마스터링 비트코인의 243p 나온 글이다. 해당 챕터를 읽어보면 머클트리가 왜 필요한지, 머클패스를 이용해서 검증하는 기술에 대해서는 이해하기 어렵지 않지만, 그럼 머클 패스를 던져주는 주체는 누구 인가에 대해서는 아리송 할 것이다. 즉 단위 기술의 이해 보다는 전반적인 스토리 이해의 부재를 느낄 것이다. (사실 저 책의 내용중 오역도 많은듯 하고, 실 저자가 친철하게 쓰지 못한 내용도 있다는 핑계를 대고 싶다. 뭐 책 두께가 한 800페이지는 되야 가능하겠지만.. 블록체인의 성경과 같은 보석같은 책에 대해 불손한 자세를 보인 것 같아서 자진 검열함) 

즉 저 책으로 처음 블록체인(비트코인)을 마주친다면 "HK가 검증 대상이면,그 쌍이 HL임을 어떻게  아는지? 이미 머클트리 상에 HK, HL 이 같이 있는 것을 확신 한다면 보낼 필요도 없는게 아닌지..?? 모든 노드가 참여하는지? 누가 보내는지?? 언제 보내는지? HK 거래는 현재 거래인가, 아니면 현재거래를 검증하기 위한 모든 과거 트랜잭션 중 하나 인가" 라는 합당한 의문들이 생기기 마련이다.

이에 대해서는 아래와 같이 추측을 했다. (사실이 아니다. or 아닐 수 도 있다.) 

"주변의 p2p의 상대 노드 중 풀노드는 거래 데이터를 받고 자신의 전체 블록체인과 대조하여 해당 거래의 유효성 확인하지만  p2p 상대가 SPV 이면 거래 데이터와 함께 "머클패스"를 보내서 검증에 참여 시킨다.

하나더

책에 있는 거래K도  현재 발생된 거래 그 자체라고 한참 오해했는데, 아니라고 추측 했다.

"현재 거래에 사용된 UTXO or 입력값 의 근거 과거 거래들 중 하나" 일 것이다.  

지금 거래의 입력값(or UTXO) 으로 사용된 코인이 합당한 것인지 어떻게 검증 할 수 있는지가 궁금해졌다.일단 현재 거래의 입력값을 검증을 위해서, 해당 입력값이 어떤 입력값에서 부터 나왔는지에 대한 내용을 블록체인에서 찾아야 한다고 짐작 할 수 있는데 아래의 두가지 궁금즘을 해결하기 위해서 먼저 비트코인을 구성하는 것들 중  4가지 구조를 한눈에 살펴보는것으로 시작하자.

@ 입력값과 UTXO 와의 구조적 차이점 (UTXO를 가지고 입력값 만들기? 출력값에서 UTXO 생성하기?) 
@ 기술적으로 입력값 or UTXO가 완성된 블록안의 머클트리에 존재하는 거래 해쉬와 어떻게 연관되는지


1. UTXO 구조

https://github.com/zoinofficial/zoin/blob/master/src/coins.h 

 CTransaction 의 잘라내진 (Pruned) 버전: 오직 메타데이터 및 UTXO 용으로 유지 

 시리얼라이즈 포맷:

  - VARINT(nVersion)

  - VARINT(nCode)

  - unspentness bitvector, for vout[2] and further; least significant byte first

  - the non-spent CTxOuts (via CTxOutCompressor)

  - VARINT(nHeight)

nCode 는 다음으로 이루어져있다.

  - bit 1: IsCoinBase()

  - bit 2: vout[0] is not spent

  - bit 4: vout[1] is not spent

  - The higher bits encode N, the number of non-zero bytes in the following bitvector.

  - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at

        least one non-spent output).

Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e

                 <><><--------------------------------------------><---->

                   |       \                            |                             /

              version   code             vout[1]                  height

 

     - version = 1

     - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)

     - unspentness bitvector: as 0 non-zero bytes follow, it has length 0

     - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35

                * 8358: compact amount representation for 60000000000 (600 BTC)

                * 00: special txout type pay-to-pubkey-hash

                * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160

     - height = 203998

 Example:                    

                01 09 0440 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b

           <><><--><---------------------------------------------------------><---------------------------------------------------><---->

             /    \      \                                |                                                                                    |                       /

    version  code  unspentness       vout[4]                                                                       vout[16]           height

 

   - version = 1

   - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,

                 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)

   - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent

   - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee

              * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)

              * 00: special txout type pay-to-pubkey-hash

              * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160

   - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4

               * bbd123: compact amount representation for 110397 (0.001 BTC)

               * 00: special txout type pay-to-pubkey-hash

               * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160

   - height = 120891

 

- UTXO 는 블록과 별개로 LevelDB에 저장된다. 사용자의 지갑에 남은 돈이 얼마인지 빠르게 알 수 있게 해 준다.
입력값에 사용된 UTXO 는 데이타베이스에서 삭제될 것이고, 출력값은 새로운 UTXO를 데이터베이스에 입력 할 것이다.
- 아직 잘 모르겠다.


gettxout "txid" n ( include_mempool )

Returns details about an unspent transaction output.

Arguments:
1. "txid"             (string, required) The transaction id
2. "n"                (numeric, required) vout number
3. "include_mempool"  (boolean, optional) Whether to include the mempool. Default: true.     Note that an unspent output that is spent in the mempool won't appear.

Result:
{
  "bestblock" : "hash",    (string) the block hash
  "confirmations" : n,       (numeric) The number of confirmations
  "value" : x.xxx,           (numeric) The transaction value in BTC
  "scriptPubKey" : {         (json object)
     "asm" : "code",       (string) 
     "hex" : "hex",        (string) 
     "reqSigs" : n,          (numeric) Number of required signatures
     "type" : "pubkeyhash", (string) The type, eg pubkeyhash
     "addresses" : [          (array of string) array of bitcoin addresses
        "address"     (string) bitcoin address
        ,...
     ]
  },
  "coinbase" : true|false   (boolean) Coinbase or not
}

Examples:

Get unspent transactions
> bitcoin-cli listunspent 

View the details
> bitcoin-cli gettxout "txid" 1

As a json rpc call
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "gettxout", "params": ["txid", 1] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/

- txid (거래아이디)와 vout 숫자(해당거래에서 돈 줄 사람중 몇번째)로 출력정보(UTXO)를 얻을 수 있구나.
- 출력정보안의 scriptPubKey 를 얻는군
- 블럭해쉬도 기본적으로 리턴해주네.

2. 거래 구조 (인용 : 책 '비트코인, 블록체인과 금융의 혁신')

 거래 구조안에는 입력값/출력값/기타등등이 있다.

입력값안에는 해제스크립트가 있고 (근데 출력값 인덱스는 뭐지?)

출력값안에는 잠금 스크립트가 있다.

하나의 거래안의  잠금 스크립트를 해제스크립트로 푸는 건가?  (아니다) 


오호~이전 UTXO를 잠그고 있군? 그럼 이전 거래를 잠그고 현재 거래에서 해제시킨다는 건가?

근데 스크립트가 뭐지?  @.@

쉽게 설명하는 블록체인, 스크립트란 뭔가요? [비트코인의 언어]
쉽게 설명하는 블록체인, 비트코인 거래의 원리와 과정 - 1
쉽게 설명하는 블록체인, 비트코인 거래의 원리와 과정 - 2 [거래의 입력값과 출력값]
비트코인 시스템에서 사용하는 암호 기술(II) - 거래 검증

gettransaction "txid" ( include_watchonly )

Get detailed information about in-wallet transaction <txid>

Arguments:
1. "txid"                  (string, required) The transaction id
2. "include_watchonly"     (bool, optional, default=false) Whether to include watch-only addresses in balance calculation and details[]

Result:
{
  "amount" : x.xxx,        (numeric) The transaction amount in BTC
  "fee": x.xxx,            (numeric) The amount of the fee in BTC. This is negative and only available for the 
                              'send' category of transactions.
  "confirmations" : n,     (numeric) The number of confirmations
  "blockhash" : "hash",  (string) The block hash
  "blockindex" : xx,       (numeric) The index of the transaction in the block that includes it
  "blocktime" : ttt,       (numeric) The time in seconds since epoch (1 Jan 1970 GMT)
  "txid" : "transactionid",   (string) The transaction id.
  "time" : ttt,            (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)
  "timereceived" : ttt,    (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)
  "bip125-replaceable": "yes|no|unknown",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);
                                                   may be unknown for unconfirmed transactions not in the mempool
  "details" : [
    {
      "account" : "accountname",      (string) DEPRECATED. The account name involved in the transaction, can be "" for the default account.
      "address" : "address",          (string) The bitcoin address involved in the transaction
      "category" : "send|receive",    (string) The category, either 'send' or 'receive'
      "amount" : x.xxx,                 (numeric) The amount in BTC
      "label" : "label",              (string) A comment for the address/transaction, if any
      "vout" : n,                       (numeric) the vout value
      "fee": x.xxx,                     (numeric) The amount of the fee in BTC. This is negative and only available for the 
                                           'send' category of transactions.
      "abandoned": xxx                  (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the 
                                           'send' category of transactions.
    }
    ,...
  ],
  "hex" : "data"         (string) Raw data for transaction
}

Examples:
> bitcoin-cli gettransaction "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d"
> bitcoin-cli gettransaction "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" true
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "gettransaction", "param=
getrawtransaction "txid" ( verbose )

NOTE: By default this function only works for mempool transactions. If the -txindex option is
enabled, it also works for blockchain transactions.
DEPRECATED: for now, it also works for transactions with unspent outputs.

Return the raw transaction data.

If verbose is 'true', returns an Object with information about 'txid'.
If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.

Arguments:
1. "txid"      (string, required) The transaction id
2. verbose       (bool, optional, default=false) If false, return a string, otherwise return a json object

Result (if verbose is not set or set to false):
"data"      (string) The serialized, hex-encoded data for 'txid'

Result (if verbose is set to true):
{
  "hex" : "data",       (string) The serialized, hex-encoded data for 'txid'
  "txid" : "id",        (string) The transaction id (same as provided)
  "hash" : "id",        (string) The transaction hash (differs from txid for witness transactions)
  "size" : n,             (numeric) The serialized transaction size
  "vsize" : n,            (numeric) The virtual transaction size (differs from size for witness transactions)
  "version" : n,          (numeric) The version
  "locktime" : ttt,       (numeric) The lock time
  "vin" : [               (array of json objects)
     {
       "txid": "id",    (string) The transaction id
       "vout": n,         (numeric) 
       "scriptSig": {     (json object) The script
         "asm": "asm",  (string) asm
         "hex": "hex"   (string) hex
       },
       "sequence": n      (numeric) The script sequence number
       "txinwitness": ["hex", ...] (array of string) hex-encoded witness data (if any)
     }
     ,...
  ],
  "vout" : [              (array of json objects)
     {
       "value" : x.xxx,            (numeric) The value in BTC
       "n" : n,                    (numeric) index
       "scriptPubKey" : {          (json object)
         "asm" : "asm",          (string) the asm
         "hex" : "hex",          (string) the hex
         "reqSigs" : n,            (numeric) The required sigs
         "type" : "pubkeyhash",  (string) The type, eg 'pubkeyhash'
         "addresses" : [           (json array of string)
           "address"        (string) bitcoin address
           ,...
         ]
       }
     }
     ,...
  ],
  "blockhash" : "hash",   (string) the block hash
  "confirmations" : n,      (numeric) The confirmations
  "time" : ttt,             (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)
  "blocktime" : ttt         (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)
}

Examples:
> bitcoin-cli getrawtransaction "mytxid"
> bitcoin-cli getrawtransaction "mytxid" true
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawtransaction", "params": ["mytxid", true] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/

- 개발 트랜잭션안에는 그 트랜잭션과 연관된 block hash가 있다. 결국 UTXO는 이전 TXID 를 가르키기 때문에 UTXO로 블럭을 찾을 수 있다는 것이고, 해당 블럭이 그 UTXO를 가지고있는지는 merkle path를 통해서 알 수 있을 것이다.


3. 블록구조 

- 채굴로 만들어진 블록의 최종 구조
- 이전 블록 해쉬,머클루트등의 블록헤더와 개별거래들을 모아둔 블록바디가 있다.
- 블록해쉬(ID)는 자체 헤더 정보를 이용해서 만들어 진다.
- 그래서  nounce 와 bits 기반으로 블럭마다 채굴을 첨부터 다시 시작해야하지.


getblock "blockhash" ( verbosity ) 

If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.
If verbosity is 1, returns an Object with information about block <hash>.
If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. 

Arguments:
1. "blockhash"          (string, required) The block hash
2. verbosity              (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data

Result (for verbosity = 0):
"data"             (string) A string that is serialized, hex-encoded data for block 'hash'.

Result (for verbosity = 1):
{
  "hash" : "hash",     (string) the block hash (same as provided)
  "confirmations" : n,   (numeric) The number of confirmations, or -1 if the block is not on the main chain
  "size" : n,            (numeric) The block size
  "strippedsize" : n,    (numeric) The block size excluding witness data
  "weight" : n           (numeric) The block weight as defined in BIP 141
  "height" : n,          (numeric) The block height or index
  "version" : n,         (numeric) The block version
  "versionHex" : "00000000", (string) The block version formatted in hexadecimal
  "merkleroot" : "xxxx", (string) The merkle root
  "tx" : [               (array of string) The transaction ids
     "transactionid"     (string) The transaction id
     ,...
  ],
  "time" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)
  "mediantime" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)
  "nonce" : n,           (numeric) The nonce
  "bits" : "1d00ffff", (string) The bits
  "difficulty" : x.xxx,  (numeric) The difficulty
  "chainwork" : "xxxx",  (string) Expected number of hashes required to produce the chain up to this block (in hex)
  "previousblockhash" : "hash",  (string) The hash of the previous block
  "nextblockhash" : "hash"       (string) The hash of the next block
}

Result (for verbosity = 2):
{
  ...,                     Same output as verbosity = 1.
  "tx" : [               (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 "tx" result.
         ,...
  ],
  ,...                     Same output as verbosity = 1.
}

Examples:
> bitcoin-cli getblock "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getblock", "params": [


4. 블록구조내의 바디 

- 3번 그림의 transaction 이 스택 형태가 아니라 해쉬값의 트리형태로 구성됨. 아래 그림은 뒤짚어 놓은 것이다.
- 2번 거래구조가 아래 그림의 입력값 A 이고, 이것을 해싱해서 나온 값들로 머클트리를 만들어서 블록구조바디에 추가
- 즉 거래 자체 데이터가 블록에 추가되는 것이 아니다.
- 원시거래구조(2번항목) 포맷은 TxID로 만들어지기 위해 이중해쉬된다. 이 txid 로 부터 머클 트리가 구성된다. 

비트코인 개발자 가이드 및 남이 그린 그림들을 토대로 전체적으로 훑어보아도 예상외로 UTXO 와 Transaction 간의 연결고리를 찾기가 힘들다.Transaction 를 위해 UTXO 는 찾을 수 있는데, 그 반대방향은 안보이는데..다시 찾아보자. 내가 TxID 에 집중해서 그런거 같은데 아마도 Address 라는 공통 분모가 있는거 같기도 하고...(이미 주화입마 상태이다.아는 것 같은데 잘 모르겠다.) 

즉 UTXO의 주인의 address 를 얻고, 그 address 를 통해서 과거 거래정보를 얻은 후에 그 TxID 를 통해 머클패스를 구성 할 것이라고 추측할 수도 있겠다 싶었는데... 웬걸 ~

이미 위에서 UTXO - TXID - 블럭해시 간에 연결고리를 발견해 놓고 먼 딴 생각을 한거냐 


위의 이미지를 보듯이, vin (입력값)에는 "이전 거래"와 "몇번째 UTXO인가" 를 가르키는 txid,vout 이 있다. 이 txid 를 매개변수로 GetRawTransaction API 를 호출하여 이전 거래를 찾거나, 그 거래(txid)를 포함하는 블록의 머클트리를 검증한다는 추론이 더 그럴싸 하다. 근데 이렇다고치면 머클패스/머클트리로 검증하는 것은 얼마나 깊이 검증해야 한다는 거냐? 즉 내가 채굴자인데 이 거래를 내 임시풀에 넣기 전에 검증 하는 용도면 채굴자 선에서 끝나는거 아닌가? 만약 임시풀에 넣고 있다가, 채굴에 성공한후에 제대로 된 블록에 넣었다고 치고 이걸 다른 노드들에게 전파 한다고 칠 때, 그 블록의 검증을 채굴,풀노드 말고 SPV 도 하나? SPV 가 하니깐 머클패스가 필요한거니 당연한건가? SPV 한데 머클패스를 보내나? 아니면 SPV 가 트랜잭션을 받으면 주변 노드한테 머클패스 달라고 요청하나?

아직 전체적인 비트코인 와꾸가 선명히 스케치 되기엔 스크립트의 이해도가 떨어져서 그런듯 하니..좀 더 힘을 내보자.
반복 만큼 좋은 것은 없다. 머리를 정돈하기 위해 아주 쉬운 기초적인 내용부터 다시 시작해보자. 


쉽게 설명하는 블록체인, 스크립트란 뭔가요? [비트코인의 언어]
쉽게 설명하는 블록체인, 비트코인 거래의 원리와 과정 - 1
쉽게 설명하는 블록체인, 비트코인 거래의 원리와 과정 - 2 [거래의 입력값과 출력값]
비트코인 시스템에서 사용하는 암호 기술(II) - 거래 검증

그리고 나서 이 글의 애니매이션을 통해 스크립트의 스택연산에 대해 감잡고 Bitcoin protocolfor developer
트랜잭션의 로우포맷에 대해 익힌후 Bitcoins the hard way: Using the raw Bitcoin protocol

비트코인 개발자 가이드의 거래 부분 을 참고로 수동으로 가상거래를 해보는 아래 멋진 글로 스크립트에 대한 이해를 끝장내자.

Part 1: Transaction Basics
Part 2: Building a Transaction By Hand

다시 한번 읽어보니, 이제 감이 잡힌거 같기도 하다. 장님 코끼리 다리 만지기를 했던 것 같다. 


Validation

비트코인에서의 검증 및 확정은 아래와 같다. - 3가지

1. 거래가 일어나고 그 거래에 대한 검증 (노드가 거래풀에 넣기 위함)  - 거래검증
   ㅁ 공개키 검증 ( A 에게 돈을 보낸 것이 맞나)
   ㅁ 공캐기로 서명 검증 (그 거래에 사용된 UTXO의 출처가 확실히 전 UTXO 부터로 인가? 혹시 내용이 변경되지 않았는가? 
   ㅁ coinbase 까지 이전 UTXO 전체 혹은 옵셔널하게 깊이를 체크한다.(라고 누군가 말하던데, 생각해 보면 깊이 1이면 충분하다고 추론한다. 마스터링 비트코인에도 이거에 대한 언급이 없다.) 

2. 노드에 의해 블록이 완성되고 그 블록에 대한 검증  -블럭검증

   ㅁ 채굴하면서 노드들은 다른 곳에서 날라온 블록에 대한 검증을 한다.블록해쉬의 정확성과 깊이를 조사한다.

3. 블록의 높이에 따른 거래 확정 
   

   ㅁ 거래가 포함된 블록이 길이(높이)를 체크한다.  
   

검증시 사용되는 것들 

 A.  LevelDB에 저장된 UTXO set 과 메타데이터 이용
 B.  블록체인 자체 이용

자 마지막 결과 !!! 여기서 머클패스를 던저주는 과정 1,2,3 중 어디일까?

당연히 거래검증 부분이다. UTXO 들에 대한 검증시 이전 UTXO 는 어떤 블록에 들어 있을 것이고, 블록은 단단히 고정되어있다.단단히 고정되어 있는 블록안에 그 UTXO가 포함된것이 확실하다면 그 UTXO 는 신뢰 할 수 있을 것인데, 풀노드라면 그냥 자신의 정보로 검증하고, SPV 일 경우 머클패스를 받기 위해 요청(Push or Pull) 할 것이다.

참 먼길을 걸어왔다. 이러한 여정을 통해서 막힌 속은 어느정도 해소 할 수 있게 되었다. 하지만 이 글은 모두 추측에 기반 하며 틀린 내용도 있을 것이다. 본 글을 사실로 받아드리지 말자. 추후에 내가 직접 C++ 소스를 까보며 정확히 확인 해야 할거 같다. 개발자적인 소명이랄까? 나는 오로지 실제 소스에 기반한 것만 사실이라고 생각한다. 조만간 C++,Golang,Scala 소스등 확인 할 것이며 관련 내용은 블로그에 작성할 것이다.


p.s

* 나중에 발견한 관련 동영상. 

Blockchain/Bitcoin for beginners 7: Blockchain header: Merkle roots and SPV transaction verification




* 마지막으로 머클트리에 먼가 문제가 있다고 느끼는 사람이 있을지도 모르겠다. 그런 사람이 실제 있다.

이 사람인데 --> 


다음 링크를 참조하자.

 https://blog.ethereum.org/2015/11/15/merkling-in-ethereum/



Comments