블록체인이란 P2P (Peer to Peer) 네트워크를 통해서 관리되는 분산 데이터베이스의 한 형태로 거래 정보를 담은 장부를 중앙 서버 한 곳에 저장하는 것이 아니라 블록체인 네트워크에 연결된 여러 컴퓨터에 저장 및 보관하는 기술을 일컫는다. 이번 포스팅에서는 어떠한 방식으로 블록이 생성되는지에 대해 간략하게 짚고 넘어가보도록 하자.
< 목차 >
- 블록의 구성요소
- crypto-js & merkle
- 제네시스 블록
1. 블록의 구성요소
블록이라는 것은 단순히 하나의 객체이다. 객체 안에 특정 정보들을 담아놓은 것이 바로 블록이다. 블록 안에 들어가는 데이터를 분류해보면 크게 다음과 같이 나눌 수 있다.
- 헤더
- 버전 정보
- 이전 블록의 해시
- 높이 : 몇번째 블록인지에 대한 정보.
- 타임스탬프 : 블록 생성 시점에 대한 정보.
- 해시
- 머클루트 : 바디 내용을 해싱한 값.
- 채굴 난이도
- 논스
- 바디
- 블록에 저장할 데이터
위에 언급된 내용들이 블록이라는 하나의 객체 안에 데이터로서 들어가게 된다. 실제 블록체인의 블록들을 살펴보면 헤더 영역과 바디 영역이 분리되어 있지는 않다. 단지 이해의 편의를 위해 헤더 영역과 바디 영역으로 구분해서 언급했을 뿐, 실제로는 헤더 영역과 바디 영역을 구분지어서 블록 객체를 생성하지 않는다.
JavaScript를 이용해 블록을 생성한다면, 블록 객체는 대략적으로 다음과 같은 형태를 띄게 된다.
const block = {
version: '1.0.0',
height: 0,
timestamp: 1654657927666,
previousHash: '',
hash: '',
merkleRoot: '',
bits: '',
difficulty: '',
nonce: '',
data: ['asdf', 'asdf', 'asdf']
}
블록 객체 안에 들어가는 정보들에 대한 내용을 살펴보도록 하자.
👉 version
해당 블록의 버전 정보가 기록된다.
👉 height
블록의 높이이다. 블록 체인에 연결된 블록의 수를 의미한다.
👉 timestamp
특정한 시각을 나타내는 문자열이다.
👉 hash
특정 블록을 식별하는데 사용되는 고유 식별자로 해시값이 들어가게 된다. 일반적으로 블록의 해시값은 해당 블록의 생성일시, 버전, 비츠(bits), 머클루트, 이전 블록의 해시, 그리고 논스(nonce)라고 불리는 임시값 등을 조합한 후 해시로 변환하여 생성한다.
참고) 해시함수(hash function) 와 해싱(hashing)에 관한 내용은 JWT와 관련하여 작성해 놓은 글이 있으니 참고하면 좋을듯 하다.
2022.03.03 - [Node.js/express] - Node.js - express (12) Buffer , Hash , JWT
👉 previousHash
이전 블록의 해시값을 의미한다.
👉 merkleRoot
블록 안에는 트랜잭션에 대한 내용이 데이터로 저장된다. 트랜잭션의 내용들을 해싱하여 해시값들로 이루어진 트리구조를 만들게 되는데 이를 "머클트리"라 한다. 그리고 머클트리의 루트에 대한 해시값이 머클루트이다.
👉 data
트랜잭션의 내용들이 블록 안에 데이터로 저장된다.
👉 difficulty , nonce
채굴 난이도와 논스 라는 개념이 존재하는데 이와 관련된 개념들은 추후에 다뤄보고자 한다.
블록에 저장된 데이터가 위변조 될 경우 머클루트의 값이 변하게 되고 그 결과 블록의 해시값이 변하게 된다. 결과적으로 블록 안의 해시값의 비교를 통해 정보의 위변조 여부를 판단하는 것이 가능해지는 것이다.
2. crypto-js & merkle
블록 안에 기록될 해시값과 머클루트값을 만들기 위해 crypto-js 라는 라이브러리와 merkle이라는 라이브러리를 사용하고자 한다. 두 라이브러리리를 이용해서 어떤식으로 해시값과 머클루트값을 생성하는지 알아보도록 하자.
우선 VSCode 터미널에서 라이브러리를 설치해준다.
npm install crypto-js
npm install merkle
👉 crypto-js/sha256
const SHA256 = require('crypto-js/sha256')
const hash = 'my first block'
console.log("result : ", SHA256(hash).toString())
console.log("length : ", SHA256(hash).toString().length)
// output
/*
result : 551da495310a462891a5bc45b36d87b7aec77be750f16696138f13c7b9643696
length : 64
*/
👉 merkle
// 머클루트를 만들어주는 라이브러리
const merkle = require('merkle')
const data = ['asdf', 'asdf', 'asdf', 'asdfasdf', 'asdfqwer', 'qwerqwer']
const merkleTree = merkle('sha256').sync(data)
const merkleRoot = merkleTree.root()
console.log(merkleRoot)
// output
// 7C91020020680EFBE45B775942839479739294C686E15D70AD824E16822D7424
3. 제네시스 블록
제네시스 블록(genesis block)은 블록체인에서 생성된 첫번째 블록을 의미한다. 첫 번째 블록이 생성된 이후 다음 블록이 지속적으로 생성되어 마치 체인처럼 이전 블록에 연결되기 때문에 제네시스 블록이 생성되었다는 것은 해당 블록체인 네트워크가 시작되었다는 상징적인 의미를 가지고 있다.
이제 JavaScript의 클래스 문법을 사용하여 첫번째 블록인 제네시스 블록을 만들어보도록 하자.
우선 블록 헤더를 만들어주는 클래스 BlockHeader를 다음과 같이 만들어주었다.
class BlockHeader {
constructor(_height, _previousHash) {
this.version = BlockHeader.getVersion()
this.height = _height
this.timestamp = BlockHeader.getTimestamp()
this.previousHash = _previousHash || '0'.repeat(64)
}
static getVersion() {
return '1.0.0'
}
static getTimestamp() {
return new Date().getTime()
}
}
const header = new BlockHeader(0)
BlockHeader 클래스 안에서 static 메소드를 사용해 타임스탬프와 버전 값을 가져올 수 있도록 만들었다. BlockHeader 클래스를 이용해 블록 헤더 객체를 생성하였는데 제네시스 블록의 경우 최초의 블록이기 때문에 previousHash 값이 존재하지 않는다. 따라서 previousHash값이 없을 경우 64자리의 0으로 이루어진 문자열이 previousHash값이 되도록 하였다.
다음으로 BlockHeader 클래스를 이용해 생성한 블록 헤더 객체의 정보와 블록 안에 저장할 데이터를 집어넣어 블록을 생성할 수 있도록 Block 클래스를 아래와 같이 만들어 보았다.
const merkle = require('merkle')
const SHA256 = require('crypto-js/sha256')
class Block {
constructor(_header, _data) {
const merkleroot = Block.getMerkleRoot(_data)
this.version = _header.version
this.height = _header.height
this.timestamp = _header.timestamp
this.previousHash = _header.previousHash
this.hash = Block.createBlockHash(_header, merkleroot)
this.merkleRoot = Block.getMerkleRoot(_data)
this.data = _data
}
static getMerkleRoot(_data) {
const merkleTree = merkle('sha256').sync(_data)
const merkleRoot = merkleTree.root()
return merkleRoot
}
static createBlockHash(_header, _merkleroot) {
const values = Object.values(_header)
const data = values.join('') + _merkleroot
return SHA256(data).toString()
}
}
Block 클래스 안에서도 static 메소드를 사용해 머클루트 값을 만들어주는 함수와 블록 해시를 만들어주는 함수를 만들었으며 머클루트와 블록해시는 각각 merkle 라이브러리와 crypto-js 라이브러리를 사용해 만들어주었다.
전체 코드는 아래와 같다.
const merkle = require('merkle')
const SHA256 = require('crypto-js/sha256')
class BlockHeader {
constructor(_height, _previousHash) {
this.version = BlockHeader.getVersion()
this.height = _height
this.timestamp = BlockHeader.getTimestamp()
this.previousHash = _previousHash || '0'.repeat(64)
}
static getVersion() {
return '1.0.0'
}
static getTimestamp() {
return new Date().getTime()
}
}
class Block {
constructor(_header, _data) {
const merkleroot = Block.getMerkleRoot(_data)
this.version = _header.version
this.height = _header.height
this.timestamp = _header.timestamp
this.previousHash = _header.previousHash
this.hash = Block.createBlockHash(_header, merkleroot)
this.merkleRoot = Block.getMerkleRoot(_data)
this.data = _data
}
static getMerkleRoot(_data) {
const merkleTree = merkle('sha256').sync(_data)
const merkleRoot = merkleTree.root()
return merkleRoot
}
static createBlockHash(_header, _merkleroot) {
const values = Object.values(_header)
const data = values.join('') + _merkleroot
return SHA256(data).toString()
}
}
const data = [ "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks" ]
const header = new BlockHeader(0)
const block = new Block(header, data)
console.log(block)
// output
/*
Block {
version: '1.0.0',
height: 0,
timestamp: 1654673896314,
previousHash: '0000000000000000000000000000000000000000000000000000000000000000',
hash: 'e3b1ea746c6d3f0aa022f90d03108773d27d89ce7d5b1ef30afdc0d90f593871',
merkleRoot: 'A6D72BAA3DB900B03E70DF880E503E9164013B4D9A470853EDC115776323A098',
data: [
'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks'
]
}
*/
'BlockChain' 카테고리의 다른 글
BlockChain - 블록체인 P2P 네트워크 만들기 (1) (1) | 2022.06.14 |
---|---|
BlockChain - TypeScript로 블록체인 만들기 (4) PoW (0) | 2022.06.14 |
BlockChain - TypeScript로 블록체인 만들기 (3) (0) | 2022.06.12 |
BlockChain - TypeScript로 블록체인 만들기 (2) (feat. Jest) (1) | 2022.06.11 |
BlockChain - TypeScript로 블록체인 만들기 (1) (0) | 2022.06.11 |