즐코

자바스크립트로 Block 만들어보기 본문

BlockChain

자바스크립트로 Block 만들어보기

YJLEE_KR 2022. 6. 8. 15:39

블록체인 

블록 - 블록을 체인형태로 연결한 자료구조

 

블록?

block = header + body 로 이루어진 객체와 같다.

(실제론 이렇게 header, body 나누진 않는다, 그냥 이해를 돕기 위한 구조라고 생각하면됨)

 

block hash값
header

Version previousBlockHash
MerkleRoot Timestamp
Difficulty (난이도) Nonce
Height  
body data (transaction) [data1, data2,....]

 

block hash값 (블록의 이름 정보)

: block header 정보를 모두 합산 후 SHA256으로 변환한 값이다. 

( 버전 + 이전 블록 해시 + 블록 총 생성 수 + 머클루트 + 타임스탬프 + 난이도 + 논스 ) => SHA256으로 변환!

 

해쉬함수 SHA256 
- 임의의 길이를 갖는 데이터를 고정된 길이의 해쉬값으로 암호화해준다.
 SHA256은 무조건 256비트(32바이트, 64글자) 데이터 길이로 출력됨 
- 데이터의 오류나 변조를 탐지할 수 있는 무결성을 제공해준다.
- 복호화가 안된다. 오로지 단방향

 

SHA256 해쉬함수 모듈

 

npm i crypto-js

 

const SHA256 = require("crypto-js/sha256");

const a = "hello hash";

console.log(SHA256(a).toString());
//e08e1d7bd3fec53b7360de39482ac30d8d1b7bedead27e013810e29095fee6fb

console.log(SHA256(a).toString().length);
// 64

 

 

- Version :

  해당 블록의 버전

 

- Height : 

   genesis block (블록체인에서 생성된 첫번째 블록) 부터 생성된 블록의 총 수 

   블록의 생성 순서를 나타내는 단위 

 

- Previous Block Hash : 

   이전 블록 해쉬

   체인으로 연결된 이전 블록의 주소 값, 즉 이전 블록의 해쉬값을 가리킨다.

 

- Timestamp :

   블록의 생성 시간

   1970년 1월 1일 자정부터 경과한 시간을 초 단위로 계산한 값

 

- Merkle Root :

   블록의 바디 부분에 저장된 데이터 (거래정보)들의 해시 트리

 

 1. 최초 원본 데이터 (각 거래정보들)를 SHA256 해쉬화

 2. 각 트랜잭션과 가까운 노드끼리 짝지어 합치고 또 SHA256 해시값 구하기

 3. 2번을 계속 하다보면 마지막 하나가 남는데 그게 바로 머클루트 값이다

 

머클트리, 머클루트값을 구해주는 모듈이 있다.

 

npm i merkle

 

merkelRoot = merkle('암호화알고리즘방식').sync(암호화할 데이터).root()

 

const merkle = require('merkle');

const data = [ 'hoochu', 'cat', 'socute', 'black', 'chicken', 'yjlee' ]

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);
// 63B374F08EE7F8197FC35D0B8F49F2B7C14C21404976D8965EDBF5549FD1775F

 

블록 js로 대애충 만들어보기

 

- Block Header 만들기

const SHA256 = require('crypto-js/sha256')
const merkle = require('merkle')

class BlockHeader{
	constructor(_height){
    	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();
    }
}

 

이 때, 클래스 함수 자체에 메서드를 설정할 수 있게 해주는 static 메서드를 쓰는 게 효율적이다.

왜냐하면, 아래처럼 this 로 클래스 내 함수를 가져다 쓸 수 있겠지만 이렇게 하면 new 생성자를 사용하여 인스턴스를 생성할 때 저 함수도 같이 생성되므로, 새로운 인스턴스가 생성될때마다 같은 함수를 반복적으로 생성해주는게 되버리니 비효율적이다.

따라서 위의 예시대로 static 정적메소드를 써준 것이다. 그러면 인스턴스 생성 전에도 메소드를 사용할 수 있게 된다.

(BlockHeader.getVersion()) 

 

 class BlockHeader {
  constructor(_height, _previousHash) {
    this.version = this.getVersion();
    this.height = _height;
    this.timestamp = this.getTimestamp();
    this.previousHash = _previousHash || "0".repeat(64);
  }
  getVersion() {
    return "1.0.0";
  }
  getTimestamp() {
    return new Date().getTime();
  }
}

const header = new BlockHeader()
header.getVersion() // 인스턴스 생성 후에 사용하는 메소드

 

- Block 만들기

   1/ merkleRoot 만들어주기

   2/ hash (헤더 정보들을 전부 합하고 해쉬화한 값 + 바디 내용을 합쳐서 해쉬화한 머클루트값) 을 해쉬한 값

 

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);
        const merkleRoot = merkleTree.root();
        return merkleRoot;
    }
    
    static createBlockHash(header,merkleRoot){
    	const values = Object.values(_header); 
        // [ '1.0.0', 0, 1654669237009, 'dsadsdsdsdds' ]
        const data = values.join('') + _merkleRoot
        return SHA256(data).toString()
    }
}

 

- 임의의 블럭 출력해보기

 

const header = new BlockHeader(0, "dsadsdsdsdds");
const data = [
  "The Times 03/Jan/2009 Chancellor on brink of seconde bailout for banks",
  "hi",
  "pls",
  "make",
  "block",
  "asap",
];
const block = new Block(header, data);

console.log(header);
console.log(block);

 

Comments