일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- node.js path
- JWT 만들어보기
- buffer.from
- cookie-parser 만들어보기
- 라우터미들웨어 분리
- 아이디 중복체크기능
- ws 라이브러리
- Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
- next 매개변수
- 라우터 분리
- nodejs파일업로드
- FormData()
- 시퀄라이즈 기본설정
- javascript기초
- express실행
- OAuth 카카오
- JWT 로그인 기능 구현
- express router
- express session
- JWT 하드코딩
- useContext
- 라우터와 미들웨어
- express.static
- 비동기파일업로드
- 세션으로 로그인 구현
- 블록 만들기
- useEffect clean up
- mysql wsl
- 라우트 매개변수
- css기초
- Today
- Total
즐코
논스 추가 + 난이도 조절 및 블록 체인 만들기 본문
저번 포스팅에 이어서 블럭에 논스를 추가하고 블럭들 간의 난이도를 조절하는 과정을 추가한다. 그리고 이 업데이트한 블록을 같은 배열안에 넣어 블록 체인 형태를 만들어보고자 한다.
1. 난이도 조절을 위한 설정값 만들기
난이도라는 건 목표값보다 낮은 해시를 찾기 위한 논스값을 연산하는 데 얼마나 오래 걸리냐이다.
즉, 새로운 블록 생성 시간이 난이도와 연관되어 있다. 늦게 생성되면 난이도가 어렵다는 것이고, 빨리 생성되면 난이도가 낮다는 것이다.
(관련 개념 포스팅 : https://yjleekr.tistory.com/75?category=1284408)
그렇기때문에 난이도의 평균시세(?)를 구하기 위해서 2가지 상수가 필요하다.
1/ 이상적으로 생각하는 블록의 평균 생성 시간
2/ 난이도 측정에 필요한 블록 개수, 간격 단위
위 2가지 상수 및 분을 초로 바꾸기 위한 단위도 config.ts 상에 넣어준다.
// src/core/config.ts
// 난이도 조정 블록 범위
export const DIFFICULTY_ADJUSTMENT_INTERVAL: number = 10;
// 블록 생성 시간 (단위 : 분) 10*60
export const BLOCK_GENERATION_INTERVAL: number = 10;
// 분->초로 바꾸기 위한 단위
export const UNIT: number = 60;
2. Chain 클래스 생성
블록은 개별적으로 존재하는 것이 아니라 체이닝되어있다. 여기선 배열에다가 블록을 추가하는 방식으로 블록 체인을 구현한다.
그렇다면, Chain 클래스는 Block을 가지고 있는 배열이므로 데이터 타입이 Block[]이 될 것이다.
애초에 첫 생성 블럭인 GENESIS 블럭을 배열에 넣고 시작한다.
각 메서드를 설명하면 다음과 같다.
- getChain() : 블록체인 자체를 반환
- getLength() : 블록체인의 길이를 반환 (몇개의 블럭이 생성되었는가)
- getLatestBlock : 체인 내의 가장 마지막, 최근 블럭을 반환
- addBlock : 블록체인 배열에 인증된 블럭을 추가하고 블럭 추가의 성공 여부를 반환
- getAdjustmentBlock : 난이도조정을 위해서 난이도를 측정하기 위한 블럭을 반환
-> 현재 블럭과 10번째 전 블럭 생성 시간을 비교할 것이므로 10번째 전 블럭을 찾아줘야한다.
-> 블럭체인 길이가 10보다 작다면, 제네시스 블럭을 반환하고, 10보다 크다면 10번째 전 블럭 반환해주기
더 자세히 말하자면,
11번째 블럭이 생성될 경우 11번째 블럭이 생성된 시간 - 0번째 블럭(제네시스 블럭)이 생성된 시간 = 10*60*10 = 6000초보다 길어지면 난이도를 낮추고 6000초보다 짧아지면 난이도를 높인다.
// src/core/blockchain/chain.ts
import { Block } from "@core/blockchain/block";
export class Chain {
public blockchain: Block[];
constructor(){
this.blockchain = [Block.getGENESIS()];
}
public getChain(): Block[] {
return this.blockchain;
}
public getLength(): number {
return this.blockchain.length;
}
public getLatestBlock(): Block {
return this.blockchain[this.blockchain.length - 1];
}
public getAdjustmentBlock() {
const currentLength = this.getLength();
const adjustmentBlock: Block = this.getLength() < DIFFICULTY_ADJUSTMENT_INTERVAL
? Block.getGENESIS()
: this.blockchain[currentLength - DIFFICULTY_ADJUSTMENT_INTERVAL];
return adjustmentBlock;
}
public addBlock(data: string[]): Failable<Block,string> {
const previousBlock = this.getLatestBlock();
previousBlock.height + 1;
const adjustmentBlock: Block = this.getAdjustmentBlock();
const newBlock = Block.generateBlock(previousBlock, data, adjustmentBlock);
const isValid = Block.isValidNewBlock(newBlock, previousBlock);
if(isValid.isError) return { isError: true, error: isValid.error };
this.blockchain.push(newBlock);
return { isError: false, value: newBlock };
}
}
3. 논스를 포함한 블록 생성
generateBlock()
블록체인 내에서 블록을 생성해주는 메소드
// src/core/blockchain/block.ts - Block 클래스
public static getGENESIS(): Block {
return GENESIS;
}
public static generateBlock(_previousBlock: Block, _data: string[], _adjustmentBlock: Block): Block {
const generateBlock = new Block(_previousBlock, _data, _adjustmentBlock);
// newBlock은 마이닝이 완료된 블럭
// generateBlock을 가지고 마이닝 관련된 코드를 작성할것
const newBlock = Block.findBlock(generateBlock);
return newBlock;
}
findBlock()
논스를 계속 1씩 증가시키면서 난이도와 그 블록해시 앞자리 0개수가 일치할 때의 논스와 해당 해시값을 블록에 업데이트해서 블록을 생성해주는 메서드
이때 블록해시는 기본적으로 16진수이므로 2진수로 바꿔야지만 앞자리 0개수를 확인할 수 있다.
public static findBlock(_generateBlock: Block): Block {
let hash: string;
let nonce: number = 0;
while (true) {
nonce++;
_generateBlock.nonce = nonce;
hash = Block.createBlockHash(_generateBlock);
const binary: string = hexToBinary(hash);
const result: boolean = binary.startsWith("0".repeat(_generateBlock.difficulty));
if (result) {
_generateBlock.hash = hash;
console.log('블록생성', binary);
return _generateBlock;
}
}
}
4. 블록 난이도 조절하기
우선 평균 블록 생성 시간(6000초) 도 정해진건 아니고, 이걸 2로 나누고 곱하는 것 또한 정해진 건 아니다.
단지 어떤 식으로 대충 난이도를 조절하는지 보여주기 위한 코드이다..실제론 더 복잡할 것이다.
// src/core/blockchain/block.ts - Block 클래스
public static getDifficulty(_newBlock: Block, _adjustmentBlock: Block, _previousBlock: Block): number {
if (_newBlock.height < 9) return 0;
if (_newBlock.height < 19) return 1;
if (_newBlock.height % DIFFICULTY_ADJUSTMENT_INTERVAL !== 0) return _previousBlock.difficulty;
const timeTaken: number = _newBlock.timestamp - _adjustmentBlock.timestamp;
const timeExpected: number = UNIT * BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; // 6000초
if (timeTaken < timeExpected / 2) return _adjustmentBlock.difficulty + 1;
else if (timeTaken > timeExpected * 2) return _adjustmentBlock.difficulty - 1;
return _adjustmentBlock.difficulty;
}
테스트 코드는 아래와 같다.
해쉬값을 hexTobinary로 2진수로 변환해보면 난이도 수와 앞의 0 개수가 일치함을 확인할 수 있다.
// src/core/blockchain/chain.test.ts
import { Chain } from "./chain";
describe("chain 함수 체크", () => {
let node: Chain = new Chain();
it("getChain() 함수 체크", () => {
console.log(node.getChain());
});
it("getLength() 함수 체크", () => {
console.log(node.getLength());
});
it("getLatestBlock() 함수 체크", () => {
console.log(node.getLatestBlock());
});
it("addBlock 함수 체크", () => {
for (let i = 1; i <= 200; i++) {
node.addBlock([`Block #${i}`]);
console.log(
`논스값 : ${node.getChain()[i].nonce}, 해쉬값 : ${node.getChain()[i].hash}, 난이도 : ${
node.getChain()[i].difficulty
}`,
);
}
console.log(node.getChain());
});
});
'BlockChain' 카테고리의 다른 글
지갑과 트랜잭션에서의 서명/검증 (Ft.개인키,공개키) (0) | 2022.06.16 |
---|---|
P2P 네트워크 / 블록체인 주고받기 (0) | 2022.06.15 |
블럭수정 + 블록 검증 코드 추가 (0) | 2022.06.14 |
작업증명 POW / nonce / 난이도 bits? (0) | 2022.06.13 |
타입스크립트로 Block 만들어보기 (0) | 2022.06.10 |