[타입스크립트로 블록체인 만들기] #5. Typescript BlockChain

min5x5·2023년 11월 7일
post-thumbnail

#5.0 Introduction

#5.1 Targets

// terminal
npm init -y // new nodejs project
npm i -D typescript // install typescript
touch tsconfig.json

typescript는 컴파일러니까, 이 파일들을 일반적인 javascript로 컴파일 시켜준다.

// tsconfig.json
{
  "include": ["src"], // typescript가 src의 모든 파일을 확인한다.
  "compilerOptions": {
    "outDir": "build", // javascript가 생성될 디렉터리를 지정한다.
    "target": "ES6", // compile 되는 javascript의 version
  }
}
// package.json
...
"scripts": {
    "build": "tsc"
  },
...

#5.2 Lib Configuration

lib configuration은 js 코드가 어디에서 동작할지 알려준다.
그래서 타입스크립트가 localStorage, Math, window 등의 타입을 이해하고 인지한다!

// tsconfig.json
{
	...
	"compilerOptions": {
    	...
        "lib": ["ES6", "dom"] // js 코드가 어디에서 동작할지 알려준다.
    
  }
}

#5.3 Declaration Files

typescript는 js로 작성된 패키지를 사용하더라도,
d.ts에 작성되어있는

// index.ts
import { init, exit } from "myPackage";

init({url: "true"})
exit(1)
// myPackage.js
export function init(config) {
    return true;
}

export function exit(code) {
    return code + 1;
}
// myPackage.d.ts 정의 파일에서 call signature, 즉 type를 써주면 된다.
interface Config {
    url: string
}
declare module "myPackage" {
    function init(config: Config): boolean;
    function exit(code: number): number;
}

#5.4 JSDoc

ts와 js를 함께 사용할 경우
js 파일은 그대로 두고, ts의 보호를 받을 수 있도록 한다.
JSDoc을 사용한다! 코멘트만 작성해서 ts의 보호를 받을 수 있다.

// tsconfig.json
{
	...
	"compilerOptions": {
    	...
   		"allowJs": true,
    
  }
}
// myPackage.js
// @ts-check
/**
 * Initializes the project
 * @param {object} config 
 * @param {boolean} config.debug
 * @param {string} config.url
 * @returns {boolean}
 */
export function init(config) {
    return true;
}

/**
 * Exits the program
 * @param {number} code 
 * @returns {number}
 */
export function exit(code) {
    return code + 1;
}
import { init, exit } from "./myPackage";

init({debug: true, url: "true"})
exit(1)

#5.5 Blocks

ts-node를 설치해서 빌드없이 타입스크립트를 실행할 수 있게 할 것이다!
프로덕션에서 사용하지는 않고, 개발환경에서 사용해서 작업속도를 빠르게 한다.
빌드없이 빠르게 새로고침하고 싶을 때 사용하는 것!

nodemon을 설치해서 자동으로 커맨드 재실행해줘서 서버를 재시작할 필요가 없다.

// package.json
...
  "scripts": {
	...
	"dev": "nodemon --exec ts-node src/index.ts"
  },

blockchain은 말 그대로 blocks of chain이다. 여러 개의 블록이 사슬처럼 묶인 것이다.
block에는 data가 들어있다. 블록체인으로 보호하고 싶은 데이터가 들어있다!
하나의 블록은 다른 블록에 연결되어있다. 연결고리는 해쉬값이다.

static 함수는 객체지향 프로그래밍에서 많이 사용된다.
클래식 인스턴스가 없어도 부를 수 있는 함수

// index.ts
import crypto from "crypto"
interface BlockShape {
    hash: string;
    prevHash: string;
    height: number;
    data: string;
}

class Block implements BlockShape{
    public hash: string;
    constructor(
        public prevHash: string,
        public height: number,
        public data: string
    ) {
        this.hash = Block.calculateHash(prevHash, height, data);
    }
    static calculateHash(prevHash:string, height:number, data: string) {
        const toHash = `${prevHash}${height}${data}`;
    }
}
// tsconfig.json
{
	...
	"compilerOptions": {
    	...
    	"esModuleInterop": true,
    	"module": "CommonJS"
    
  }
}

#5.6 DefinitelyTyped

타입스크립트로 작성되지 않은 패키지를 import 할 때,
crypto 패키지 안의 함수를 타입스크립트한테 설명해줄 파일이 필요하다!
사용하는 라이브러리나 패키지마다 정의파일을 만들 수는 없다.

// Error: 'crypto' is declared but its value is never read.
import crypto from "crypto";

// nodejs의 모든 것에 대해 ts에게 알려줄 수 있다.
// package에 대한 .d.ts.파일들이 설치된다!

npm i -D @types/node

#5.7 Chain

import crypto from "crypto";

interface BlockShape {
  hash: string;
  prevHash: string;
  height: number;
  data: string;
}

class Block implements BlockShape {
  public hash: string;
  constructor(
    public prevHash: string,
    public height: number,
    public data: string
  ) {
    this.hash = Block.calculateHash(prevHash, height, data);
  }
  static calculateHash(prevHash: string, height: number, data: string) {
    const toHash = `${prevHash}${height}${data}`;
    return crypto.createHash("sha256").update(toHash).digest("hex");
  }
}

class BlockChain {
  private blocks: Block[];
  constructor() {
    this.blocks = [];
  }
  private getPrevHash() {
    if (this.blocks.length === 0) return "";
    return this.blocks[this.blocks.length - 1].hash;
  }
  public addBlock(data: string) {
    const newBlock = new Block(
      this.getPrevHash(),
      this.blocks.length + 1,
      data
    );
    this.blocks.push(newBlock);
  }
  public getBlocks() {
    // return this.blocks 를 하면 중간에 해킹당할 수 있다! data가 안전하지 않음!
    // blockchain.getBlocks().push(new Block("xxxx", 1111, "Hacked"))
    return [...this.blocks];
  }
}

const blockchain = new BlockChain();
blockchain.addBlock("First");
blockchain.addBlock("Second");
blockchain.addBlock("Third");

console.log(blockchain.getBlocks());

#5.8 Conclusions

profile
삶에 변화를 만드는 개발자

0개의 댓글