즐코

타입스크립트로 Block 만들어보기 본문

BlockChain

타입스크립트로 Block 만들어보기

YJLEE_KR 2022. 6. 10. 02:33

기본적으로 ts 를 쓰기 위한 세팅은 완료하고 시작한다.

(해당 블록엔 아직까지 논스와 난이도에 대한 개념이 들어가지 않은 상태이고, 이건 추후 다른 포스팅에서 추가할 예정) 

1. 블록의 타입 지정하기

   

- @types 폴더 만들고 그 안에 Block.d.ts 파일 생성

 

1/ block header 정의

: version, height, timestamp, previousHash 

 

2/ block 정의

 : 우선 블럭 자체가 블럭헤더를 품고 있기 때문에 extends 키워드로 IBlockHeader를 상속받아오기

 

 - merkleRoot : 바디의 data를 해싱한 값이기 때문에 block에서 만들어줘야함 

 - hash : block header의 해싱값과 block body 데이터의 해싱값인 merkleRoot 를 합친 값이므로 이 역시 block에서 만들기

-  data : 여기에 거래 정보, 내역을 담는다고 하는데, 아직 기초만 배우고 있으므로 string 형태의 데이터를 담은 배열을 받음.

// @types/Block.d.ts

declare interface IBlockHeader {
  version: string;
  height: number;
  timestamp: number;
  previousHash: string;
}

declare interface IBlock extends IBlockHeader {
  hash: string;
  merkleRoot: string;
  data: string[];
}

 

2. 블록 헤더 만들기

implements 키워드 : class의 interface에 충족하는지 여부를 체크할 때 사용한다. 

만약, implements 한 interface의 타입 중 하나라도 없다면 에러를 반환한다.

타입 체크 위한 용도 O / 내부 값 자동으로 변경 X

 

extends : 클래스를 그대로 상속하고 싶을 때 사용
부모(상위)클래스의 모든 속성, 메서드를 가지고 오므로 일일이 정의할 필요가 없다.

implements : 새로운 클래스를 만들 때 특정 클래스 모양과 똑같이 정의하고 싶을 때 사용한다.
상속받는 개념이 절대 아니다.

 

implements 키워드로 앞서 정의한 IBlockHeader 타입을 가져온다. 

* 위에서 설명한대로 정의한 타입을 그대로 가져오고 싶기 때문

 

 1/ 블록 헤더가 낳을 객체의 타입을 먼저 정의해주고

 2/ 인스턴스 생성 시 받을 인자를 정의해준다.

    기본적으로 블록은 이전 블록과 연결되어 있으므로 이전 블록을 인자로 받아야한다.

// src/core/blockchain/blockHeader.ts

export class BlockHeader implements IBlockHeader {
  public version: string;
  public height: number;
  public timestamp: number;
  public previousHash: string;

  constructor(_previousHash: IBlock) {
    this.version = BlockHeader.getVersion();
    this.height = _previousHash.height + 1;
    this.timestamp = BlockHeader.getTimestamp();
    this.previousHash = _previousHash.hash;
  }

  public static getVersion() {
    return "1.0,0";
  }

  public static getTimestamp() {
    return new Date().getDate();
  }
}

 

3. 블록 만들기

기본적으로 data를 가져와서 merkleRoot 및 hash 를 만들어줘야한다.

merkleRoot 와 hash값을 만들려면 두 가지 라이브러리가 필요한 건 어제 배웠다.

다만, 타입스크립트 환경에선 타입 정의 모듈도 필요하므로 추가로 깔아준다. 고맙게도 이 두 라이브러리는 패키지를 제공해준다.

npm i merkle
npm i -D @types/merkle
npm i crypto-js
npm i -D @types/crypto-js

 

1/ BlockHeader를 상속해오고 (extends) IBlock 타입 모양을 그대로 따른다 (implements)

 

2/ 새로운 블럭 객체 인스턴스를 생성할 때 block header 를 만든거처럼 필요한 인자는 이전 블록이다.

 

3/ merkleRoot와 hash값을 만드는 함수는 이미 이전 포스팅에서 정리했으므로 설명은 생략한다. 

// src/core/blockchain/block.ts

import { BlockHeader } from "./blockHeader";
import merkle from "merkle";
import SHA256 from "crypto-js/sha256";

export class Block extends BlockHeader implements IBlock {
  public hash: string;
  public merkleRoot: string;
  public data: string[];

  constructor(_previousBlock: Block, _data: string[]) {
    super(_previousBlock);
    const merkleRoot = Block.getMerkleRoot(_data);
    this.hash = Block.createBlockHash(this);
    this.merkleRoot = merkleRoot;
    this.data = _data;
  }
  public static getMerkleRoot(data: string[]) {
    const merkleTree = merkle("sha256").sync(data);
    const merkleRoot = merkleTree.root();
    return merkleRoot;
  }
  public static createBlockHash(block: Block): string {
    const { version, timestamp, merkleRoot, previousHash, height } = block;
    const value: string = `${version}${timestamp}${merkleRoot}${previousHash}${height}`;
    return SHA256(value).toString();
  }
}

 

4. 테스트 돌려서 새로운 블럭 출력해보기

1/ 블럭을 생성하려면 이전 블럭이 있어야 하는데,

    최초 생성 블럭인 genesisBlock을 사용하기로 함. 이건 우선 하드코딩으로 만들어준다..

    다만, 가져온 Block 클래스와 모양이 같아야하므로 타입 지정 시 Block을 사용해준다. 

 

2/ new 생성자로 이미 만들어둔 BlockHeader, Block 클래스를 가져다가 인스턴스를 생성해준다. 

// src/core/blockchain/block.test.ts

import { Block } from "./block";
// import { Block } from "@core/blockchain/block'
import { BlockHeader } from "./blockHeader";
// import { BlockHeader } from "@core/blockchain/blockheader";

describe("block 검증", () => {
  const genesisBlock: Block = {
    version: "1.0.0",
    height: 0,
    hash: "0".repeat(64),
    timestamp: 1231006506,
    previousHash: "0".repeat(64),
    merkleRoot: "0".repeat(64),
    data: ["Hello Block"],
  };
  it("Block 생성", () => {
    const data = ["Block #2"];
    const header = new BlockHeader(genesisBlock);
    const newBlock = new Block(genesisBlock, data);
    console.log(newBlock);
  });
});

 

블럭이 아래와 같이 만들어졌다!

 

Comments