
npm i initnpm i crypto-js merkle hex-to-binarynpm i -D jestconst hexToBinary = require("hex-to-binary");
난이도와 논스를 사용해 문제를 품
여기서의 문제는 difficulty알고리즘 이라고 한다.
difficulty 알고리즘은 2진수로 변화하여 앞의 0의 개수와 difficulty를 비교하여 difficulty보다 0의 개수가 많으면 문제를 해결한 것이다.
Block의 암호화된 hash는 64자의 16진수 수로 이루어져 있다.
hash를 2진수로 바꾸고 2진수 수의 제일 앞에서부터 연속되는 0의 개수가 difficulty보다 크면 해결한 것이고 아니면 해결하지 못한 것으로 처리한다.
hash == AAAA => 1010 1010 1010 1010
hash == 1AAA => 0001 1010 1010 1010
16진수 3을 10진수로 바꾸면 3이고 2진수로 바꾸면 11인데 컴퓨터는 0011이라고 인식한다.
코드
// 문제를 푼다.
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
}
// 제네시스 블록 생성 시 전달하지 않으므로 예외 처리
if (_adjustmentBlock && _config) {
this.updateBlock({
previousDifficulty: _previousBlock.difficulty,
adjustmentDifficulty: _adjustmentBlock.difficulty,
adjustmentTimestamp: _adjustmentBlock.timestamp,
DAI: _config.DAI,
averageGenerationTime: _config.averageGenerationTime,
});
}
const chain = new Chain();
for(let i = 0; i<200; i++){
chain.createBlock([`test block ${i}`]);
}
// 여기여기 추가했음 ㅠㅠ
console.log(hashBinary);
console.log(hashBinary.slice(0, this.difficulty)); this.data = _data;
console.log(this);cd chainnode chain.js 로 실행 -> 200에 다가갈 수록 점점 블록 생성 시간이 느려짐을 확인할 수 있다.
// 블록 10개 당 생성에 걸리는 시간(블록 한 세대)
// #BLOCK_GENERATION_INTERVAL = 10;
#BLOCK_GENERATION_INTERVAL = 1;
// 시간의 단위 설정(60s * 1000mx : 1m(1분))
// #TIME_UNIT = 60*1000;
#TIME_UNIT = 1*1000;
} 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;
}
}

const hexToBinary = require("hex-to-binary");
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);
});
});

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