블록체인의 체인 구현

이재영·2023년 9월 5일
0

BlockChain

목록 보기
3/13
post-thumbnail

어제는 마이닝을 통해 블록을 생성을 하는 것을 배웠다면,
오늘은 그 블록들을 배열로 가지고 있는 체인을 다뤄보자.

chain.ts

import Block from "@core/block/block"
import { GENESIS } from "@core/config"
import { Failable } from "@core/interface/failable.interface"

class Chain{
  	//⭐⭐⭐⭐⭐⭐⭐
  	// chain 은 배열이고, 배열의 요소들은 Block 타입이여야한다.
    private chain : Block[] = [GENESIS];
    private readonly INTERVAL = 10;
    
    //현재 체인을 반환하는 함수
    get(){
        return this.chain;
    }
    
    //길이를 반환하는 함수
    length(){
        return this.chain.length;
    }

    // 체인에 마지막 블록 반환 함수
    latestBlock(){
        return this.chain[this.length()-1];
    }

    // 블록 추가 메서드
    addToChain(receiveBlock : Block){
        this.chain.push(receiveBlock);
        return this.latestBlock();
    }
	//⭐⭐⭐⭐⭐⭐⭐
    // 블록을 조회하는 메서드
    getBlock(callbackFn : (block : Block) => boolean){

        const findBlock  = this.chain.find(callbackFn)

        if(!findBlock) throw new Error("찾은 블록이 없음");
        return findBlock;   
    }

    // 블록의 높이로 블록을 조회하는 함수
    getBlockByHeight(height: number){
        return this.getBlock((block : Block)=> block.height === height);
    }

    // 블록의 해시로 찾는 함수
    getBlockByHash(hash : string) {
        return this.getBlock((block : Block)=> block.hash === hash);
    }

    // 10번째 블록들을 찾는 함수 현재 위치에서
    getAdjustBlock(){
        const {height} = this.latestBlock();
        const findHeight = height < this.INTERVAL ? 1 : Math.floor(height / this.INTERVAL) * this.INTERVAL;

        // 10번째들의 블록의 높이로 블록을 조회해서 블록 반환
      	//⭐⭐⭐⭐⭐⭐⭐
        return this.getBlockByHeight(findHeight);
    }
    
    // 다른 네트워크로 체인을 보낼 때 문자열로 바꿔서
    serialize(){
        return JSON.stringify(this.chain);
    }

    // 다른 네트워크에서 체인을 받을 때 객체로 바꿔서
    deserialize(chunk : string){
        return JSON.parse(chunk);
    }

    // 상대방 체인과 본인의 체인을 비교
    replaceChain(receivedChain : Block[]): Failable<undefined,string>{

        // 본인의 체인과 상대방의 체인을 검사하는 로직
        // 실제 네트워크에서는 더 복잡한 로직이 들어가 있겠지만 
        // 전체 배경이 중요하다. 우리는 체인의 길이를 비교하는 로직을 구현할 것.
        // 머클루트 ,해시값, 체인 전체 검증 등등의 로직이 더 추가되어 있을건데
        // 중요한건 체인의 길이를 비교하는것.(롱기스트 체인 룰 : 더 긴 체인이 정답이다)

        // 상대방의 체인의 마지막 블록
        const latestReceivedBlock : Block = receivedChain[receivedChain.length -1];

        // 본인의 마지막 블록
        const latestBlock : Block = this.latestBlock();

        if(latestReceivedBlock.height === 0){
            return {isError : true, value : "상대방 네트워크 체인은 마지막 블록이 최초 블록이다."}
        }

        if(latestReceivedBlock.height <= latestBlock.height){
            return {isError : true, value : "상대방 네트워크의 체인보다 내 체인이 같거나 크다."}
        }

        // 상대방의 체인이 내 체인보다 길면
        // 내 체인을 교체한다 전달받은 체인으로 업데이트
        this.chain = receivedChain;

        return {isError : false, value : undefined};
    }

    // 현재 블록 생성 시점에서
    // 이전 -10번째 블록 구하기
    // 현재 높이값 < 10 : 최초블록을 반환하고
    // 현재 높이값 > 10 : -10번째 블록 반환.
    // 이전 10번째 블록의 생성 시간의 차이를 구해서
    // 그 차이가 블록 생성 주기 보다 빠르면 난이도를 증가
    // 생성주기가 느리면 난이도 하락
    // 비트코인 기준으로 블록의 생성 시간은 10분에 1개
    // 10개가 생성되는 시간은 100분
    // 100분 보다 빠르면 난이도를 상승시키고
    // 100분도 보다 느리면 난이도를 하락시킨다.

    getAdjustmentBlock(){
      	// 내 체인의 길이
        const currentLength = this.length();
        const adjustmentBlock : Block = this.length() < this.INTERVAL ? GENESIS : this.chain[currentLength-this.INTERVAL];

        // 최초블럭 or -10번째 블록반환
        return adjustmentBlock;
    }
}
export default Chain;

🔎코드 이해가 부족한 부분

	  let findHeight =1;
      getBlockByHeight(findHeight); 코드로

      getBlockByHeight(height: number){
        	//number 에는 1
        	return this.getBlock((block : Block)=> block.height === height);
    } 이 함수가 호출되고,
      //⭐⭐⭐⭐⭐⭐⭐
	  //getBlock 함수의 매개변수는 callback 함수가 들어가야하고,
      //매개변수는 block 이고 Block 타입을 가지고 반환값은 boolean 값이여한다.
      //전달한 매개변수는 Block 타입이고, 반환값은 block.height === height 코드로 bool 이다.
      //그래서 bool 값이 true 면 find 함수가 height가 일치하는 요소를 찾아 findBlock에 반환한다.
      
      getBlock(callbackFn : (block : Block) => boolean){

      const findBlock  = this.chain.find(callbackFn)
	
      // findBlock 의 값이 없으면 아래 코드 실행.
      if(!findBlock) throw new Error("찾은 블록이 없음");
      return findBlock;   
    } 이 함수까지 호출된다.
    

block.test.ts

it("블록 체인 추가", ()=>{
        newChain = new Chain();
        newChain.addToChain(newBlock);
    })

    it("네트워크 체인 비교(롱기스트 체인 룰)",()=>{
        newChain2 = new Chain();
        newChain2.replaceChain(newChain.get());
    })

    it("이전 10번째 블록 or 최초 블록 ", ()=>{
        // 현재 블록을 생성한다 가정하고
        // 현재 블록이 생성된 시간이 이전 10번째 블록으로부터 얼마나 걸렸는지
        // 확인을하고 블록의 정해진 생성주기보다 빠르면 난이도를 올리고 아니면 내린다.
        // console.log("latestBlock---------------------",newChain.latestBlock());
        for (let i = 0; i < 20; i++) {
            let block = new Block(newChain.latestBlock(),["block"])
            newChain.addToChain(block);            
        }
    })
profile
한걸음씩

0개의 댓글