블록체인 논스

efforthye·2023년 1월 13일

비공개

목록 보기
5/6
post-thumbnail

상위 폴더에 라이브러리 설치

  • 이것저것

    npm i init
    npm i crypto-js merkle hex-to-binary
    npm i -D jest
  • 이미지
  • block 폴더와 chain 폴더 가져옴

block.js

1. 라이브러리 가져오기

const hexToBinary = require("hex-to-binary");

2. block class 내부 해시생성 아래에 문제풀이함수 만들기

  • 난이도와 논스를 사용해 문제를 품

  • 여기서의 문제는 difficulty알고리즘 이라고 한다.

  • difficulty 알고리즘은 2진수로 변화하여 앞의 0의 개수와 difficulty를 비교하여 difficulty보다 0의 개수가 많으면 문제를 해결한 것이다.

  • Block의 암호화된 hash는 64자의 16진수 수로 이루어져 있다.

  • hash를 2진수로 바꾸고 2진수 수의 제일 앞에서부터 연속되는 0의 개수가 difficulty보다 크면 해결한 것이고 아니면 해결하지 못한 것으로 처리한다.

  • hash == AAAA => 1010 1010 1010 1010

    • difficulty가 0이면 "0"이 0개 있으면 해결이다. 즉, 현재는 해결이다.
    • difficulty가 1이면 "0"이 1개 있으면 해결이다. 즉 현재는 해결하지 못했다.
  • hash == 1AAA => 0001 1010 1010 1010

    • difficulty가 0이면 "0"이 0개 있으면 해결이다. 즉, 현재는 해결이다.
    • difficulty가 1이면 "0"이 1개 있으면 해결이다. 즉, 현재는 해결이다.
  • 16진수 3을 10진수로 바꾸면 3이고 2진수로 바꾸면 11인데 컴퓨터는 0011이라고 인식한다.

    • 16진수 A => 10진수 10 => 2진수 1010
    • 16진수 F => 10진수 15 => 2진수 1111 이렇게 4자리로 표현할 수 있다.
    • difficulty가 1이면 2진수에서 0으로 시작 == 16진수에서 8보다 작으면 된다. == 16진수의 8은 2진수의 1000이고 그보다 작은 0111, 즉 7 이하의 수이면 가능하다.
    • 만약 difficulty가 2면 hash의 첫 자리가 몇 이하면 될까? : 0011 => 3 => 16진수에서도 3 이하이면 됨
  • 코드

        // 문제를 푼다.
      updateBlock(){
    
          // 현재 해시를 2진수로 변환한다.
          let hashBinary = hexToBinary(this.hash);
    
          // startWith : string의 메서드로 시작하는 문장을 확인해 
          // 시작하지 않았으면 난이도 만큼 0이 반복될 때까지 while문을 돌린다. 
          while(!hashBinary.startsWith("0".repeat(this.difficulty))){
    
              // hash가 변경될 수 있도록 nonce를 증가시킨다.
              this.nonce += 1;
    
              // 블록 생성 시간은 chain에 추가되는 시간이기 때문에
              // 문제 풀이 시점을 생성 시간으로 재정의 한다. (시간을 다시 설정해준다.)
              // while에서 나온 상태면 이미 해시가 다시 만들어진 상태이기 때문에 여기서 설정한다.
              this.setTimestamp();
    
              // 시간이 다시 설정되었기 때문에 기준 시간과 비교해 난이도를 재설정한다.
              // 여기는 매개변수가 들어가야 한다. // 받아와야 함
              // difficultyOptions라는 변수로 넣은 이유 : updateBlock메서드 또한 매개변수로 해당 정보를 받아와야 하기 때문
              // 해당 정보? : 난이도 옵션들...
              this.getDifficulty(difficultyOptions);
    
              // 해시를 새로 만들고 2진수로 변환해 while의 조건문에 해당하지 않는지 확인
              // while의 조건문이 부정이기 때문에 while에서 빠져나오면 문제 해결이다.
              this.hash = Block.createHash(this);
              hashBinary = hexToBinary(this.hash);
    
          }// while end
    
      }

3. 블록 클래스의 생성자 부분에 추가

  • this.hash = Block.createHash(this); 아래에 적기
            // 제네시스 블록 생성 시 전달하지 않으므로 예외 처리
            if (_adjustmentBlock && _config) {
                this.updateBlock({
                    previousDifficulty: _previousBlock.difficulty,
                    adjustmentDifficulty: _adjustmentBlock.difficulty,
                    adjustmentTimestamp: _adjustmentBlock.timestamp,
                    DAI: _config.DAI,
                    averageGenerationTime: _config.averageGenerationTime,
                });
            }

chain.js

  • 체인에 블록 200개 추가(32->200)
const chain = new Chain();
for(let i = 0; i<200; i++){
    chain.createBlock([`test block ${i}`]);
}
  • 주석 처리
    1. 블록 생성시간 console.log() 지우기
    2. 블록 클래스의 문제풀이 함수(updateBlock) 맨 아래에 콘솔로그 추가
          // 여기여기 추가했음 ㅠㅠ
          console.log(hashBinary);
          console.log(hashBinary.slice(0, this.difficulty));
    1. this.data = data; 아래에 콘솔로그 추가
          this.data = _data;
           console.log(this);
    1. chain.js의 console.log(chain.chain); 주석처리하기
  • 터미널 확인
    1. chain 폴더 이동 cd chain
    2. node chain.js 로 실행 -> 200에 다가갈 수록 점점 블록 생성 시간이 느려짐을 확인할 수 있다.

시간 조절(1초에 10개씩 생성하도록)

chain.js chain class

  • 블록 10개 생성 시간 1으로 변경 및 타임유닛 1*1000으로 변경
	// 블록 10개 당 생성에 걸리는 시간(블록 한 세대)
    // #BLOCK_GENERATION_INTERVAL = 10;
    #BLOCK_GENERATION_INTERVAL = 1;

    // 시간의 단위 설정(60s * 1000mx : 1m(1분))
    // #TIME_UNIT = 60*1000;
    #TIME_UNIT = 1*1000;

block.js

  • getDifficulty else부분
    • 기존코드
        } else {
            // 10개 전 블록과 현재 블록의 생성 시간 차이
            const timeToken = this.timestamp - adjustmentTimestamp;

            // console.log("블록 생성 시간 : ", this.timestamp);
            // console.log("10개 전 블록 생성 시간 : ", adjustmentTimestamp);
            // console.log("10개 이전과 현재 생성 시간 차이 : ", timeToken);
            // console.log("10개당 블록 생성 시간 기준 : ", averageGenerationTime);

            // 이전 10개 생성 시간이 5분 이하로 걸렸을 때(시간이 절반이하로 적게 걸렸을 때)
            if (timeToken < averageGenerationTime * 0.5) {
                // 난이도를 올려 시간이 더 걸릴 수 있게 조절한다.
                this.difficulty = adjustmentDifficulty + 1;
            } else if (timeToken > averageGenerationTime * 1.5) {
                // 이전 10개 생성 시간이 15분보다 많이 걸렸을 때
                // 난이도를 낮춰서 시간이 덜 걸릴 수 있게 조절한다.
                this.difficulty = adjustmentDifficulty - 1;
            } else {
                // 시간이 내가 설정한 대로 잘 되어 있으니까 난이도를 그대로 둔다.
                this.difficulty = adjustmentDifficulty;
            }
        }
  • 수정코드
        } else {
            // 10개 전 블록과 현재 블록의 생성 시간 차이
            const timeToken = this.timestamp - adjustmentTimestamp;

            // console.log("블록 생성 시간 : ", this.timestamp);
            // console.log("10개 전 블록 생성 시간 : ", adjustmentTimestamp);
            // console.log("10개 이전과 현재 생성 시간 차이 : ", timeToken);
            // console.log("10개당 블록 생성 시간 기준 : ", averageGenerationTime);

            // 이전 10개 생성 시간이 0.9초 이하로 걸렸을 때(시간이 절반이하로 적게 걸렸을 때)
            if (timeToken < averageGenerationTime * 0.9) {
                // 난이도를 올려 시간이 더 걸릴 수 있게 조절한다.
                this.difficulty = adjustmentDifficulty + 1;
            } else if (timeToken > averageGenerationTime * 1.1) {
                // 이전 10개 생성 시간이 1.1초보다 많이 걸렸을 때
                // 난이도를 낮춰서 시간이 덜 걸릴 수 있게 조절한다.
                this.difficulty = adjustmentDifficulty - 1;
            } else {
                // 시간이 내가 설정한 대로 잘 되어 있으니까 난이도를 그대로 둔다.
                this.difficulty = adjustmentDifficulty;
            }
        }

난이도 변경 확인 가능

  • 채굴 속도에 따라 difficulty가 변경함을 확인할 수 있다.

테스트

block.test.js

  1. 라이브러리 가져오기

    const hexToBinary = require("hex-to-binary");

  2. updateBlock 체크 describe

    describe("updateBlock check", () => {
        const previousBlock = new Block(["이전 블록"]);
        previousBlock.height = 29;
        previousBlock.difficulty = 10;
        const adjustmentBlock = new Block(["단위개수 전 블록"]);
        adjustmentBlock.height = 20; // 이전블록 29, 현재블록 30, 단위개수전 20
        adjustmentBlock.difficulty = 11; // 9~11까지 가능

        it("난이도에 따라 문제 풀이가 정상적으로 작동했는가?", () => {
            const newBlock = new Block(
                ["asdf"],
                previousBlock,
                adjustmentBlock,
                { DAI: 10, averageGenerationTime: 60 * 1000 }
            );

            expect(
                hexToBinary(newBlock.hash).startsWith("0".repeat(newBlock.difficulty))
            ).toBe(true);
            
        });

    });
  • 결과
  1. difficulty 체크 describe

    describe("difficulty check",()=>{

    });

0개의 댓글