[TypeScript] TypeScript로 블록체인 만들기 - 노마드 코더

노승철 ·2021년 2월 26일
0

TypeScript

목록 보기
1/1
post-thumbnail

노마드 코더의 니꼴라스 강좌를 따라하며 TypeScript를 활용해 간단한 블록체인 구현하기. 나의 강의 목적은 TypeScript 사용 해보는 것.
블록체인의 개념은 깊게 이해하지 못 함.

🌙 프로젝트 설정

  1. 프로젝트 생성 아래 명령으로 프로젝트 셋팅하기.
  2. TypeScript 설치하기.
  • yarn init
  • yarn global add typescript

Config 파일 설정

  1. tsconfig.json : 프로젝트 생성 후 tsconfig.json 타입스크립트 설정파일을 생성한다.
    타입 스크립트 컴파일 옵션을 설정해서 자동으로 컴파일 되게 설정했다.
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "ES6",
        "sourceMap": true,
        "outDir": "dist"
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
} 
  1. package.json : 타입스크립트.ts 파일을 컴파일 하게 되면 자바스크립트 파일이 자동으로 생성되는데 start를 지정해 컴파일이 성공 했을 때 자바스크립트 파일이 생성되는 위치를 지정해준다.
"scripts": {
    "start": "tsc-watch --onSuccess \" node dist/index.js \" "
  }

🤌🏼 코드를 작상하기 전..

  • 블록의 Hash 값을 생성하기 위해  "crypto-js" 라이브러리를 설치한다.
    crypto-js 라이브러리는 문자들을 결합시켜준다.
  • 블록체인은 말 그대로 블록들을 체인으로 연결하여 여러개의 블록을 가진 구조를 말하는 것이다. 이 프로젝트에서는 하나의 블록을 Default로 생성 하여 그 블록을 중심으로 여러개의 블록을 생성하여 연결 짓는 것이 목적이다.

index.ts

import * as CryptoJS from 'crypto-js'; 

class Block {
    static calculateBlockHash = (index: number, previousHash:string, data: string, timestamp: number):string => {
      /* 
      	CryptoJS 라이브러리는 문자들을 결합해 하나의 문자열로 만든다.      	
      */
        return CryptoJS.SHA256(index + previousHash + data + timestamp).toString();
    }

    static validateStructure = (aBlock : Block) =>
        typeof aBlock.index === "number" &&
        typeof aBlock.hash === "string" &&
        typeof aBlock.previousHash === "string" &&
        typeof aBlock.data === "string" &&
        typeof aBlock.timestamp === "number";          

    public index : number;
    public hash : string;
    public previousHash : string;
    public data : string;
    public timestamp : number;    

    constructor(index: number, hash: string, previousHash: string, data: string, timestamp: number) {
        this.index = index;
        this.hash = hash;
        this.previousHash = previousHash;
        this.data = data;
        this.timestamp = timestamp;
    }
}

/* Default 블록 생성. */
const genesisBlock : Block = new Block(0, "20202020", "", "Hello", 123456);

/* 전체 블록들을 담을 배열. */
let blockchain : Block[] = [genesisBlock];

/* 현재 생성된 블록들을 가져오는 함수 */
const getBlockchain = () :Block[] => blockchain;
/* 현재 블록들 중에 가장 최근에 생성된 블록 가져오는 함수 */
const getLatestBlock = () : Block => blockchain[blockchain.length - 1];
/* 새로운 블록 생성시간 만들기 함수. */
const getNewTimeStamp = () : number => Math.round(new Date().getTime() / 1000);

/* 
	- 블록을 생성하는 함수.
    - Block 클래스의 내장 함수인 calculateBlockHash를 사용하여
    새로운 블록을 생성할 수 있게 Param을 전달한다. 
    - 생성된 Block을 기존 블록들을 담는 List에 Push
    
*/
const createNewBlock = (data: string): Block => {
    const previousBlock: Block = getLatestBlock();
    const newIndex: number = previousBlock.index + 1;
    const newTimeStamp: number = getNewTimeStamp();
    const newHash: string = Block.calculateBlockHash(
        newIndex, 
        previousBlock.hash, 
        data, 
        newTimeStamp
    );
    const newBlock: Block = new Block(
        newIndex,
        newHash,
        previousBlock.hash,
        data,
        newTimeStamp
    );

    addBlock(newBlock);
    return newBlock;
}

/*
	생성된 블록을 받아 해쉬를 생성한다.
*/
const getHashForBlock = (aBlock: Block) : string => 
    Block.calculateBlockHash(aBlock.index, aBlock.previousHash, aBlock.data, aBlock.timestamp);

/*
	생성된 블록과 최근의 블록 유효성 검사.
*/
const isBlockValid = (candidateBlock : Block, previousBlock : Block) : boolean => {
  	/* 생성된 블록이 Block 클래스의 타입과 일치하지 않을 경우 */
    if(!Block.validateStructure(candidateBlock)) {
        return false;
    }
  	/* 최근의 블록의 index와 생성된 블럭의 index + 1 값과 생성된 index 값이 같지 않을 경우 */
    else if(previousBlock.index + 1 !== candidateBlock.index) {
        return false;
    }
  /* 
  	최근의 블록의 해쉬값과 생성된 이전의 해쉬값이 일치 하지 않은 경우.
  */
    else if(previousBlock.hash !== candidateBlock.previousHash) {
        return false;
    }
  /*
  	생성된 해쉬 값이 일치하지 않은 경우
  */
    else if(getHashForBlock(candidateBlock) !== candidateBlock.hash) {
        return false;
    } else {
        return true;
    }
}

/* 유효성 검사 결과가 True일 경우 block 리스트에 추가. */
const addBlock = (candidateBlock: Block) : void => {
    if(isBlockValid(candidateBlock, getLatestBlock())) {
        blockchain.push(candidateBlock);
    }
}

createNewBlock("second block");
createNewBlock("third block");
createNewBlock("fourth block");

console.log(getBlockchain());

export {};

함수 또는 객체, 요소 하나하나의 Type을 지정해주기 때문에 결과의 Type을 미리 예측할 수 있다는 점이 아주 매력적인 TypeScript이다.

profile
👨🏻‍💻 #developer#일상#공부#기록

0개의 댓글