javascript로 blockchain의 block기능 구현해보기

서기영·2022년 4월 28일

블록체인은 p2p(peer to peer) 방식으로 블록이라는 형태에 데이터들이 저장된다.
이 말을 다르게 하면, 블록체인 네트워크상에서 거래에 참여한 모든 유저들이(노드) 같은 정보를 가지게 됨을 의미한다.

이런 네트워크를 이해하기에 앞서, 먼저 블록에 대해 알아보고자 한다.
블록에는 어떤 정보들이 담길까?

블록을 구성하는데는 여러 요소들이 있지만, 크게 2가지로 구분해보면 블록 헤더와 블록바디로 나눌 수 있다. 헤더에는 블록의 유일성을 알리는 해시값을 포함해, 블록이 생성된 시간(timestamp), 이전블록해시, 난이도 등의 정보가 담긴다. 바디에는 실제 블록에 요청된 거래에 대한 정보가 담긴다고 볼 수 있다. 아래의 그림은 일반적인 블록의 구조도이다.

블록 해시는 블록의 버전, 이전 블록 해시, 머클 루트, 타임, bits, 논스 정보를 모두 더한 합을 SHA256으로 변환한 결과 값이다. 64비트의 16진수로 되어있으며, input값이 다르면 다른 결과값이 도출된다. 필자는 일부 정보로만(아래에 있다) 블록을 생성하는 코드를 짜 볼 것이다.

index : 블록체인의 높이
data : 블록에 포함된 모든 데이터 (트랜잭션 포함)
timestamp : 블록이 생성된 시간
hash : 블록 내부 데이터로 생성한 sha256 값 (블록의 유일성)
previousHash : 이전 블록의 해쉬 (이전 블록을 참조)

block.js

import CryptoJS from 'crypto-js'; // 해시 도출에 필요한 모듈(sha256함수 내장)

class Block {	// 블록 클래스 선언
    constructor(index, data, timestamp, hash, previousHash) // 생성자
    {
        this.index = index;
        this.data = data;
        this.timestamp = timestamp;
        this.hash = hash;
        this.previousHash = previousHash;
    }
}

// 해시 생성
const calculateHash = (index, data, timestamp, previousHash) => {
    return CryptoJS.SHA256((index + data + timestamp + previousHash).toString()).toString();
}

// 블록 정보 조회
const getBlocks = () => { 
    return blocks;
}

// 제네시스 블록 생성
const createGenesisBlock = () => {
    const genesisBlock = new Block(0,'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks', new Date().getTime() / 1000, 0, 0);
    
    genesisBlock.hash = calculateHash(genesisBlock.index, genesisBlock.data, genesisBlock.timestamp, genesisBlock.previousHash);
    
    return genesisBlock;
}

// 블록 생성
const createBlock = (blockData) => {
    const previousBlock = blocks[blocks.length - 1];
    const nextIndex = previousBlock.index + 1;
    const nextTimeStamp = new Date().getTime() / 1000;
    const nextHash = calculateHash(nextIndex, blockData, nextTimeStamp, previousBlock.hash);
    const newBlock = new Block(nextIndex, blockData, nextTimeStamp, nextHash, previousBlock.hash);

    if (isValidNewBlock(newBlock, previousBlock)) {
        blocks.push(newBlock);
        return newBlock;
    }

    console.log('failed to create new block!');
    return null;
}

// 블록정보 데이터 타입 검사
const isValidBlockStructure = (newBlock) => {
    if (typeof (newBlock.index) === "number"
    && typeof (newBlock.data) === "string"
    && typeof (newBlock.timestamp) === "number"
    && typeof (newBlock.hash) === "string"
    && typeof (newBlock.previousHash) === "string"
    ) {
        return true;
    }
    return false;
}

// 블록 무결성 검사
const isValidNewBlock = (newBlock, previousBlock) => {
	// 1. 인덱스 비교
    if (newBlock.index !== previousBlock.index + 1) {
        console.log("invalid index!");
        return false;
    }
    // 2. 해시값 비교
    else if (newBlock.previousHash !== previousBlock.hash) {
        console.log("invalid previous hash!");
        return false;
    }
    // 3. 데이터 타입 비교
    else if (!isValidBlockStructure(newBlock)) {
        console.log('invalid block structure!');
        return false;
    }

    return true;

}

const blocks = [createGenesisBlock()];
getBlocks();
createBlock('blockchain is fun!');
getBlocks();

블록 무결성 검사를 통과하면 블록데이터가 생성되고 getBlocks()로 블록정보 조회를 조회한다.
여기까지 블록 생성부터 블록 조회까지 간단하게 살펴보았다. 다음엔 http 서버와 p2p서버에서 블록 데이터를 다루는 내용을 다뤄보겠다.

profile
진정한 배움은 가르침과 기록을 오가며 실현된다.

0개의 댓글