TYPESCRIPT

BlockChain 만들기 - 3)Blockchain 만들기

dodop 2021. 5. 18. 16:36

이제 타입스크립트로 블록체인을 만들어보자 .

 

index.ts를 다음과 같이 바꿔주자. 

타입스크립은 다음과 같이 타입자체를 설정할 수 있다. 

class Block {//블록 구조를 만든다. 
    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;
    }
}

//첫번째 블록을 만들자.(여기서 :Block은 타입이 블록이라는 뜻이다.)
const genesisBlock:Block = new Block(0, "202020202020", "", "Hello", 123456)

//블록으로 이루어진 배열에 첫번째 블록을 넣는다.
let blockchain: [Block] = [genesisBlock];

console.log(blockchain);

export {};//타입스크립트의 방식(이걸 해야 선언이 가능하다) 

 

 

콘솔창에 뜨는 것을 확인할 수 있다. 

 

 

이제 해시를 계산해서 생산해내는 기능을 만들어 블럭을 만들어보자 .

crypto-js를 기능을 사용할 것이다. 

yarn add crypto-js

 

설치하고 나서 다음과 같이 import해준다. (자바스크립트의 방식과는 다르다)

import * as CryptoJS from "crypto-js";

 

자바스크립트에서 블록체인을 만들때는 클래스 밖에 생성했지만, 

타입스크립트는 클래스 안에 생성해준다. 

이는 블록클래스 안에서 항상 사용할 수 있는 method라는 의미다. 

즉, 블록을 생성했을 때에만 (블록타입일때만)사용이 가능한 함수라는 의미다. (여기서 static을 써야 Block.~의 형태로 사용이 가능하다)

import * as CryptoJS from "crypto-js";

class Block {//블록 구조를 만든다. 
    public index: number;
    public hash: string;
    public previousHash : string;
    public data: string;
    public timestamp : number;

    static calculateBlockHash = (index:number, previousHash:string, timestamp:number, data:string ):string=>CryptoJS.SHA256(index+previousHash+timestamp+data).toString();
   
    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;
    }
}

 

 

여러가지 함수를 추가해서 만들어보자. 

import * as CryptoJS from "crypto-js";

class Block {//블록 구조를 만든다. 
    public index: number;
    public hash: string;
    public previousHash : string;
    public data: string;
    public timestamp : number;

    static calculateBlockHash = (index:number, previousHash:string, timestamp:number, data:string ):string=> CryptoJS.SHA256(index+previousHash+timestamp+data).toString();
   
    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;
    }
}


//첫번째 블록을 만들자.(여기서 :Block은 타입이 블록이라는 뜻이다.)
const genesisBlock:Block = new Block(0, "202020202020", "", "Hello", 123456)

//블록으로 이루어진 배열에 첫번째 블록을 넣는다.
let blockchain: Block[] = [genesisBlock];

console.log(blockchain);

//블록들을 가지고 오는 함수
const getBlockchain = () :Block[] => blockchain;

//가장 마지막 블록을 가지고 오는 함수 (최근것)
const getLatestBlock = () :Block => blockchain[blockchain.length-1];
 
//새로운 시간을 가지고 오는 함수(현재)
const getNewTimeStamp = ():number=> Math.round(new Date().getTime()/1000);

 

새로운 블록을 만드는 함수를 생성하고 결과를 보자 .

//새로운 블록을 만드는 함수
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, newTimestamp, data);
    const newBlock:Block = new Block(newIndex, newHash, previousBlock.hash, data,newTimestamp );
    return newBlock;
};

console.log(createNewBlock("hello"), createNewBlock("bye bye"));

 

여기서 인덱스가 계속 1인 이유는 블록 배열안에 원래 블록인 genesisblock만을 가지고 있기 때문이다. 

 

이번엔 만든 것들이 validate한지 확인하자. 

 

import * as CryptoJS from "crypto-js";

class Block {//블록 구조를 만든다. 

    //블록의 구조가 맞는지 확인하는 static함수
    static validateStructure = (aBlock:Block) : boolean => 
        typeof aBlock.index ==="number" && 
        typeof aBlock.hash ==="string" && 
        typeof aBlock.previousHash==="string" && 
        typeof aBlock.timestamp ==="number" &&
        typeof aBlock.data ==="string";


}


//두개의 block을 비교해서 타당한지 확인 
const isBlockValid = (candidateBlock:Block, previousBlock:Block):boolean =>{
    if(!Block.validateStructure(candidateBlock)){
        return false;
    }else if(previousBlock.index+1 !== candidateBlock.index){
        return false;
    } else if(previousBlock.hash!== candidateBlock.previousHash){
        return false;
    } //여기는 따로 해쉬를 계산해서 들어온 블록의 해쉬가 실제로 있는지 확인한다. 
    else if()
}

 

블록의 해쉬를 가져오는함수를 따로 작성해준다. 

const getHashforBlock = (aBlock:Block):string =>Block.calculateBlockHash(aBlock.index,aBlock.previousHash, aBlock.timestamp, aBlock.data )

//두개의 block을 비교해서 타당한지 확인 
const isBlockValid = (candidateBlock:Block, previousBlock:Block):boolean =>{
    if(!Block.validateStructure(candidateBlock)){
        return false;
    }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;
    }
};

 

이제 블록을 추가하자. 

//블록을 추가하자. 
const addBlock = (candidateBlock:Block):void=>{
    if(isBlockValid(candidateBlock, getLatestBlock())){
        blockchain.push(candidateBlock);
    }
}

 

createNewBlock함수에 addBlock함수를 추가하자. 

//새로운 블록을 만드는 함수
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, newTimestamp, data);
    const newBlock:Block = new Block(newIndex, newHash, previousBlock.hash, data,newTimestamp );
    
    addBlock(newBlock);
    return newBlock;


};

 

 

다음과 같이 실행해보면, 


createNewBlock("second block");

createNewBlock("third block");

createNewBlock("fourth block");

console.log(blockchain);

 

 

결과

올바르게 생성됐음을 확인할 수 있다. 

모두 previousHash값을 가지고 있다.