[TypeScript] 연습: 체인 만들기

summereuna🐥·2023년 9월 6일

TypeScript

목록 보기
13/13

📚 일단 작업 효율 높이기 위해 스크립트 수정 및 패키지 추가


작업 효율을 높이기하기 위해 스크립트를 수정하자.

  • start를 실행하면 build폴더 안의 index.js 파일을 실행하도록 스크립트에 추가

📍 package-lock.json

{
  "name": "typechain",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "start": "node build/index.js" // 노드 실행하는거 추가
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "typescript": "^5.2.2"
  }
}

현재 워크 플로우는 먼저 빌드한 다음 실행해야 한다.

  • npm run build && npm start
    그러면 먼저 빌드되고 build 폴더 안의 index.js가 실행된다.

📚 ts-node 설치하여 ts -> js로 빌드 없이 바로 타입스크립트 실행하기

좀 귀찮으니 빌드 없이 타입스크립트를 실행할 수 있는 패키지를 다운 받아 사용하자.

  • npm i -D ts-node
  • 이 패키지는 프로덕션에서 사용하는 패키지는 아니고, 개발 환경에서만 사용하는 패키지로, 빌드 없이 빠르게 새로고침하고 싶을 때 사용할 수 있다.

스크립트에 ts-node를 추가하여 사용하자.

  • "dev": "ts-node src/index.ts"
  • 빌드를 계속 수행하면 작업 속도가 느려지는데, ts-node를 사용하면 빌드한 다음 코드를 실행하지 않아도 ts-node가 컴파일할 필요없이 타입스크립트 코드를 대신 실행해주기 때문에 작업 속도가 개선될 수 있다.
  • 이렇게 바로 ts를 실행해 준다.

📚 nodemon 설치하여 자동으로 커맨드 재실행하기

nodemon을 사용하면 수정된게 있으면 자동으로 커맨드 재실행해준다.

  • "dev": "nodemon --exec ts-node src/index.ts"
  • 이제 직접 서버를 재시작할 필요가 없다.
    즉, npm run dev를 다시 입력하지 않아도 내용이 바뀌면 자동으로 커맨드를 재실행해준다.

    이렇게 바뀐 것을 저장할 때마다 자동으로 커맨드를 재실행해준다.

연습: 블록 체인 만들기

블록체인이란?

여러 개의 블록이 사슬 처럼 묶인 것을 블록체인이라고 한다.

  • 그 블록 안에는, 블록체인으로 보호하고 싶은 데이터가 들어 있다.
  • 블록들은 다른 블록에 묶여 있다. 사슬처럼 연결되어 있다.
  • 그리고 그 연결고리는 해쉬값이다.

1. 블록 클래스 만들기


tsconfig.json 수정

{
  "include": ["src"],
  "compilerOptions": {
    "outDir": "build",
    "target": "ES6",
    "lib": ["ES6"],
    "strict": true,
    "esModuleInterop": true,
    "module": "CommonJS"
  }
}
  • nodeJS 앱을 만들거기 때문에 allowJs 없애고, lib에서 "DOM"도 없앤다.

  • 그리고 esModuleInterop을 추가하여 import * as crypto from "crypto"; 라고 적는 대신 import crypto from "crypto";를 작성할 수 있게 한다.

  • moduleCommonJS를 넣어준다. 브라우저 앱을 만든다면 umd를 사용하면 된다.

크립토를 사용하려고 하는데 아래 처럼 뜰 경우 정의 파일을 직접 만들어야 할까? 노ㅗㅗ우

Cannot fint module 'crypto' or its corresponding type declarations.

👉 Definitely Typed으로 가서 집단 지성의 힘을 보자 😇
이 깃 레파지토리는 오직 타입 정의로만 이루어진, npm에 존재하는 거의 모든 패키지들에 대해 타입 정의한 파일이 있다.
집단 지성 폼 미쳤다!

이걸 긁어 올수도 있지만 그냥 npm 으로 패키지를 설치하면 된다.

  • npm i -D @types/node
    그럼 nodejs를 위한 타입을 다 설치해 준다.
    근데 지금 타입스크립트 버전에는 기본으로 nodejs 타입은 포함되어 있는거 같기도.. ㅇㅇ...

최근에 패키지 만드는 사람들은 npm 패키지를 설치하면 d.ts 파일 함께 포함하기 시작했다고함.

블록 클래스 만들기

📍 index.ts

//해시 하기 위해 노드JS의 크립토 사용
import crypto from "crypto";

//인터페이스로 BlockShape 객체 타입 설정
interface BlockShape {
  hash: string;
  prevHash: string; //이전 해쉬 값
  height: number; //1,2,3,4... 같이 블록의 위치를 표시해주는 숫자
  data: string; // 보호할 데이터
}

//1. Block 클래스 만들기
class Block implements BlockShape {
  //타입 명시
  public hash: string;
  //블록 생성하기
  //1-1. 생성자 메서드 constructor()로 블록의 기본 상태 설정하기
  constructor(
    public prevHash: string,
    public height: number,
    public data: string
  ) {
    //hash 변수 초기화
    this.hash = Block.calculateHash(prevHash, height, data);
  }

  //1-2. Block 객체에 포함되는 메서드 생성하기
  //static 메서드는 클래스 안에서 사용하는 메서드로 클래스 인스턴스가 없어도 부를 수 있다.
  static calculateHash(prevHash: string, height: number, data: string) {
    //데이터 해쉬값 생성하기
    const toHash = `${prevHash}${height}${data}`;
    //크립토로 toHash 해시하여 반환하기
    return crypto.createHash("sha256").update(toHash).digest("hex");
  }
}

//2. BlockChain 클래스(=블락 모은거) 생성하기
class BlockChain {
  //타입 명시
  private blocks: Block[]; //Block 클래스의 배열

  //2-1. constructor() 메서드로 BlockChain 객체의 기본 상태 설정하기
  constructor() {
    //BlockChain.blocks 속성은 배열인데, 이 배열에 Block들을 담을 예정
    this.blocks = [];
    //클래스 생성자 파라미터는 일단 비워두기
  }

  ///////////////////////////////////////
  //2-2. BlockChain 객체에 속한 메서드들

  //이전 해쉬값 불러오는 pirvate 함수
  private getPrevHash() {
    //blocks의 길이가 0이라면, 즉 블록체인에 아무것도 없다면 이전 해시 값이 없으므로 "" 리턴
    if (this.blocks.length === 0) return "";
    return this.blocks[this.blocks.length - 1].hash;
    //blocks에 뭔가 있다면 `마지막 블럭의 해쉬(hash)값(배열은 0부터 시작이니 -1 해주면 됨)` 리턴
  }

  //새로운 블록을 추가할 때, 블록에 저장하고 싶은 데이터 보내줘야함
  public addBlock(data: string) {
    //새로운 블록 생성하기
    const newBlock = new Block(
      this.getPrevHash(), //이전 해시값
      this.blocks.length + 1, //height 값
      data // data 값
    );

    //생성한 블럭 넣기
    this.blocks.push(newBlock);
  }

  //블록에 접근하는 public 함수
  public getBlocks() {
    return this.blocks;
  }
  ///////////////////////////////////////
}

//2-3. BlockChain 클래스의 인스턴스 생성하기
const blockchain = new BlockChain();

//2-4. BlockChain 클래스의 인스턴스에서 메서드 사용하여 새로운 블럭 추가하기
blockchain.addBlock("1 block");
blockchain.addBlock("2 block");
blockchain.addBlock("3 block");
blockchain.addBlock("444block");

//2-5. 블럭체인이 가진 블럭 get하는 메서드 사용하여 어떤 블럭 있는지 보기
console.log(blockchain.getBlocks());

  • 블럭체인이 가진 blocks 배열을 가져오기 위해, 블럭체인 클래스의 인스턴스인 blockchaingetBlocks() 메서드를 사용하면 콘솔에 이렇게 뜬다.
  • 처음 블럭에는 해시 값이 없고, 두 번째 블럭의 해시값의 이전 값이 처음 블럭의 해시값과 동일하게 잘 넣어진 것을 확인할 수있다.

보안 문제 해결하기

하지만 여기에 문제가 있는데 바로 보안 문제이다.
현재 상태에서는 누구든지 여기 있는 여러 단계를 거치지 않고도 블록체인에 새로운 블록을 추가할 수 있다.

이유

  • blocks는 블록체인 안의 블록 정보이고private 값이다.
  • 그럼에도 불구하고 블록을 리턴할 때, this.blocks를 반환하고 있기 때문에, blockchain.getBlock().push(new Block("아무해시값",0, "너해킹당함ㅋ"))로 배열에 접근하여 아무런 해쉬값,아무런 높이값, 아무런 데이터 넣어 만든 새로운 블럭을 배열에 더해버릴 수도 있다.
  • 그럼 해킹당해버리는 것임 ^^.. 다른 블럭이랑 연결도 안되고 블록체인이 아니게 되버리는 것임 ㅠ

해결 방법

이를 위해 getBlock() 메서드의 반환 값을 변경하자.

  • 배열 안에 있는 데이터를 가진 아에 새로운 배열을 리턴한다.
public getBlocks() {
  return [...this.blocks]; //🔥 새로운 배열 리턴
}


그럼 아까처럼 배열에 접근하려고 해도 블록체인의 state에 연결되지 않기 때문에 문제가 되지 않는다.

profile
Always have hope🍀 & constant passion🔥

0개의 댓글