0. 목차
1. 개요
2. Block의 구조
3. Block의 생성
1. 개요
드디어 시작하는 블록체인
블록체인은 결국 블록을 체인을 통해 연결 시켜 놓은 것인데,
오늘은 그중에서 블록의 구조와 class를 이용해 블록을 생성하는 방법에 대해 알아보려한다.
블록을 생성함에 있어 체인으로 연결된 이전 블록의 정보를 가져오는 부분은
현 상황에서는 체인에 대한 기술지식이 없으므로,
기술부채로 남겨두고 우선은 제네시스 블록(최초의 블록)을 만드는 형태로 만들어 보려한다.
2.Block 의 구조
블록은 크게 두가지로 구성되어 있다.
- 헤더 : 블록에 대한 정보가 담겨있음
- version: 블록헤더의 버전을 의미
- height: 해당 블록의 인덱스
- previousBlockHash
- hash: 해당 블록의 이름이 되는 암호화된 문자열
- 나머지 헤더에 대한 내용을 hash화 해서 저장
- merkleRoot: body의 내용을 hash 화 해서 저자읃
- difficulty: 난이도를 의미 함
- nonce
- timestamp: 블록이 생성된 날짜
- 바디 : 거래내역(data)이 들어간다
- data: 배열형태로 들어감
const block = {
version: '1.0.0',
previousBlockHash:'adsfasfdas',
height: 0,
hash:'aadsf',
merkleRoot: 'adsfasd',
difficulty: 0,
nonce: 0,
timestamp: 123123
data:['adfas','adsfa','adfa','asdf']
}
코드로 보면 이런 형태이다.
data 프로퍼티를 body
그 외의 내용을 header라고 한다.
difficulty 와 nonce 는 mining 에 대한 내용을 이해하기 전까지는 기술부채로 남겨두겠다.
위의 내용을 정확히 이해하기 위해서는 hash 에대해 먼저 알아야 한다.
npm init -y
npm install crypto-js
const SHA256 = require('crypto-js/sha256');
const a = 'hello hash';
const b = 'b';
console.log(SHA256(a).toString());
//e08e1d7bd3fec53b7360de39482ac30d8d1b7bedead27e013810e29095fee6fb
console.log(SHA256(a).toString().length); //64
console.log(SHA256(b).toString());
console.log(SHA256(b).toString().length); //64
hash에 대해 간략하게 알기위해 위의 코드를 작성했다.
어떤 문자열을 넣든 간에 hashing을 거치면 64글자의 암호화 된 문자열로 변환된다.
또한, hash는 단방향 암호화 이므로, 암호화 된 문자열에서 원래의 문자열로 돌아가지 못한다.
merkleRoot
merkleRoot를 만드는 방법은
어렸을 때 해봤던 애정도 체크? 그거랑 매우 비슷하다.
body.data 배열에 들어있는 내용을
0번 인덱스와 1번인덱스를 더해서 hash화 한걸 hashA,
2번 인덱스와 3번 인덱스를 더해서 hash화 한걸 hashB,
hashA와 hashB를 더해서 hash 화 한걸 hashC라고 하겠다.
그림으로 보면 좀 더 이해가 빠르다.
공부를 할수록 그림판 실력이 늘어난다.
이 hashC 가 merkleRoot가 된다.
이걸 직접 코드로 구현한다면
조금 번거로롭다.
그래서 어떤 똑똑한 사람이 라이브러리를 만들어 줬다.
npm install merkle
const merkle = require('merkle');
const data = ['adf', 'asdfasd', 'asdfasdf', 'qtrefdhgf', 'asdf'];
const merkleTree = merkle('sha256').sync(data);
console.log(merkleTree);
/*
{
root: [Function: root],
level: [Function: level],
depth: [Function: depth],
levels: [Function: levels],
nodes: [Function: nodes],
getProofPath: [Function: getProofPath]
}
*/
const merkleRoot = merkleTree.root();
console.log(merkleRoot);
//7D9DFEFE7C6CBFD9DAA96D34A018CEED4CD12BA7EF72227E53AD377EFB76A708
위 코드의 merkleRoot 가 블록 헤더의 merkleRoot 에 할당된다.
3. Block의 생성
우선은 할 수 있는 만큼의 기본 지식은 만들어 졌으니,
이번엔 직접 블록을 생성 하는 class 코드를 작성해보려고 한다.
수업 때는 js로 하였지만,
추가로 ts로도 구현 해보았다.
3-1. javascript
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 Number(new Date());
}
}
const blockHeader = new BlockHeader(0);
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 = merkleRoot;
this.data = _data;
}
static getMerkleRoot(_data) {
const merkleTree = merkle('sha256').sync(_data);
return merkleTree.root();
}
static createBlockHash(_header, merkleRoot) {
const values = Object.values(_header);
const data = values.join('') + merkleRoot;
return SHA256(data).toString();
}
}
const data = ['adf', 'asdfasd', 'asdfasdf', 'qtrefdhgf', 'asdf'];
const block = new Block(blockHeader, data);
console.log(block);
BlockHeader를 만드는 class 와
Block을 만드는 class를 따로 나누어서 작업을 했다.
- Block의 구조에서 crypto-js와 merkle에 대한 내용을 잘 이해했다면,
그 다음은 평범한 자바스크립트의 class 문법이다.
3-2. typescript
import merkle from 'merkle';
import SHA256 from 'crypto-js/sha256';
class BlockHeader {
version: string;
height: number;
timestamp: number;
previousHash: string;
constructor(_height: number, _previousHash: string = '') {
this.version = BlockHeader.gerVersion();
this.height = _height;
this.timestamp = BlockHeader.getTimestamp();
this.previousHash = _previousHash || '0'.repeat(64);
}
static gerVersion(): string {
return '1.0.0';
}
static getTimestamp(): number {
return Number(new Date());
}
}
class Block extends BlockHeader {
merkleRoot: string;
data: string[];
hash: string;
constructor(_data: string[], _height: number = 0) {
super(_height);
this.merkleRoot = Block.getMerkleRoot(_data);
this.data = _data;
this.hash = Block.createBlockHash(this);
}
static getMerkleRoot(_data: string[]): string {
const merkleTree = merkle('sha256').sync(_data);
return merkleTree.root();
}
static createBlockHash(_block: Block): string {
const values =
Object.entries(_block)
.filter((v) => v[0] !== 'data')
.map((v) => v[1].toString())
.join('');
return SHA256(values).toString();
}
}
const data: string[] = ['adf', 'asdfasd', 'asdfasdf', 'qtrefdhgf', 'asdf'];
const block = new Block(data);
console.log(block);
/*
Block {
version: '1.0.0',
height: 0,
timestamp: 1654673821803,
previousHash: '0000000000000000000000000000000000000000000000000000000000000000',
merkleRoot: '7D9DFEFE7C6CBFD9DAA96D34A018CEED4CD12BA7EF72227E53AD377EFB76A708',
data: [ 'adf', 'asdfasd', 'asdfasdf', 'qtrefdhgf', 'asdf' ],
hash: '446fc6104c85a6dbe820ec165d00b98285c5835ae5632164c40e07b274b6d70e'
}
*/
Block class 코드가 자바스크립트로 작성한 것과는 조금 달라졌다.
extends를 사용한 부분과
그에 따라, createBlockHash 메서드의 코드가 조금 달라졌다.
자바스크립트와 타입스크립트의 차이가 아니라,
Block class 에서 BlockHeader의 인스턴스를 parameter로 받아 하나하나 입력 해주는 부분이 비효율적이라고 느껴졌고,
때문에, extends를 활용해서 코드를 조금 수정했다.
다만 extends를 사용했기 때문에 createBlockHash 의 코드가 조금 난잡해지긴 했는데,
이렇게 코드를 작성하는게 조금 더 객체지향적 프로그래밍에 걸맞지 않나 라는 생각이 든다.
'경일 > Block-chain' 카테고리의 다른 글
[Blockchain/블록체인] Wallet(지갑)/PrivateKey(개인키)/PublicKey(공개키)/account(계정) 톺아보기 (0) | 2022.06.20 |
---|---|
[Blockchain/블록체인] P2P 서버로 받은 블록 검증 및 업데이트 (0) | 2022.06.15 |
[Blockchain/블록체인] P2P 네트워크 이용하여 블록정보 주고 받기 (0) | 2022.06.14 |
[Blockchain/블록체인] P2P서버로 네트워크 구축 (0) | 2022.06.14 |
[Block-chain/블록체인] chain/difficulty/mining 구현 (1) | 2022.06.12 |
댓글