{
"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
좀 귀찮으니 빌드 없이 타입스크립트를 실행할 수 있는 패키지를 다운 받아 사용하자.
npm i -D ts-node"dev": "ts-node src/index.ts"
nodemon을 사용하면 수정된게 있으면 자동으로 커맨드 재실행해준다.
"dev": "nodemon --exec ts-node src/index.ts"npm run dev를 다시 입력하지 않아도 내용이 바뀌면 자동으로 커맨드를 재실행해준다.
여러 개의 블록이 사슬 처럼 묶인 것을 블록체인이라고 한다.
{
"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";를 작성할 수 있게 한다.
module에 CommonJS를 넣어준다. 브라우저 앱을 만든다면 umd를 사용하면 된다.
크립토를 사용하려고 하는데 아래 처럼 뜰 경우 정의 파일을 직접 만들어야 할까? 노ㅗㅗ우
Cannot fint module 'crypto' or its corresponding type declarations.
👉 Definitely Typed으로 가서 집단 지성의 힘을 보자 😇
이 깃 레파지토리는 오직 타입 정의로만 이루어진, npm에 존재하는 거의 모든 패키지들에 대해 타입 정의한 파일이 있다.
집단 지성 폼 미쳤다!

이걸 긁어 올수도 있지만 그냥 npm 으로 패키지를 설치하면 된다.
npm i -D @types/node최근에 패키지 만드는 사람들은 npm 패키지를 설치하면 d.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 배열을 가져오기 위해, 블럭체인 클래스의 인스턴스인 blockchain에 getBlocks() 메서드를 사용하면 콘솔에 이렇게 뜬다.하지만 여기에 문제가 있는데 바로 보안 문제이다.
현재 상태에서는 누구든지 여기 있는 여러 단계를 거치지 않고도 블록체인에 새로운 블록을 추가할 수 있다.
blocks는 블록체인 안의 블록 정보이고private 값이다.this.blocks를 반환하고 있기 때문에, blockchain.getBlock().push(new Block("아무해시값",0, "너해킹당함ㅋ"))로 배열에 접근하여 아무런 해쉬값,아무런 높이값, 아무런 데이터 넣어 만든 새로운 블럭을 배열에 더해버릴 수도 있다.
이를 위해 getBlock() 메서드의 반환 값을 변경하자.
public getBlocks() {
return [...this.blocks]; //🔥 새로운 배열 리턴
}

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