블록체인의 체인?
import { Block } from "@core/block/block";
import { GENESIS } from "@core/config";
import { Failable } from "@core/interface/failable.interface";
class Chain {
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(receivedBlock: Block) {
this.chain.push(receivedBlock);
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 curremtlemgth = this.length();
const adjustmentBlock: Block =
this.length() < this.INTERVAL
? GENESIS
: this.chain[curremtlemgth - this.INTERVAL];
// 최초 블럭 or -10번쨰 블럭 반환
return adjustmentBlock;
}
}
export default Chain;
중요한 내용은 다들어있다. Block 타입의 chain이있고 Block.generate 를통해 생성하게된다면 chain에 Push하게된다 이어진 하나의 배열로 여기면 된다.
시간에따른 난도 조절
블럭하나를 생성하는데 시간이 너무 오래걸린다면 난도를 조절해야한다. 비트코인에도 도입되어있는 시스템으로 2000개이전의 블럭의 생성시과 마지막으로 생성된 블럭의 시간을 비교하며 특정 시간을 넘어가면 난이도를 조절한다. 계산을 위한 블럭을 얻기위해서는 adjustmnentblock latestblock Block이 사용된다.
이를위해 블럭 컨스트럭쳐의 값을 일부 수정했다.
this.difficulty = _previousBlock.difficulty;
난도를 이전 블러의 난이도를 불러오는 방식으로 설정했다.
static generateBlock(
_previousBlock: Block,
_data: string[],
timestamp: number
): Block {
console.log(timestamp);
if (timestamp < 500) {
console.log("난이도 증가");
console.log("전", _previousBlock.difficulty);
_previousBlock.difficulty = _previousBlock.difficulty + 1;
console.log("난이도증가후", _previousBlock.difficulty);
console.log(_previousBlock);
} else if (timestamp > 600) {
console.log("난도 감소", _previousBlock.difficulty);
_previousBlock.difficulty = _previousBlock.difficulty - 1;
}
const generateBlock = new Block(_previousBlock, _data);
// 마이닝을 통해서 블록의 생성권한을 받은 블록을만들고
const newBlock = Block.findBlock(generateBlock);
return newBlock;
}
또한 블럭을 생성할때 시간차를 timestamp로 받아서 난이도를 증가할지 감소시킬지 판단하게끔했다.
테스트 코드
it("이전 10번째 블록 or 최초 블록", () => {
// 현재 블록을 생성한다 가정하고
// 현재 블록이 생성된 시간이 이전 10번째 블록으로부터 얼마나 걸렸는지
// 확인을 하고 블록의 정해진 생성 주기보다 빠르면 난이도를 올리고 아니면 내린다.
newChain = new Chain();
for (let i = 0; i < 50; i++) {
let asd = newChain.getAdjustmentBlock();
let asd2 = newChain.latestBlock();
let block = Block.generateBlock(
newChain.latestBlock(),
["block"],
asd2.timestamp - asd.timestamp
);
console.log(
"체인의 마지막 블럭 - 10개전 블럭 시간 ",
asd2.timestamp - asd.timestamp
);
newChain.addToChain(block);
}
console.log(newChain);
});
해당 테스트를 통해 확인할수있다.
다만
고민했던 사항
처음에 어떻게 이전의 값을 설정할지 감이 잡히지않아서 static으로 diff를 설정해서 계속 값에 접근해서 바꿀있게 할까 고민했지만.
해당하는 방법은 많은 위험이있고 매끄럽지않다는 생각이들었다. 이미 컨트스트럭처로 이전 블럭의 값을 받아서 초기화해준다는 점을이용해서 난도를 설정해주는것이 매끄럽다고 후에 생각햇다.
이미 활성화된 생태꼐에서는 이전 블럭이 존재하기에 처음부터 난도를 높여가며 설정할필요가없다.
다만 현재 테스트하는 코드는 일시적으로 생성된 제네시스 블럭에서 난이도를 받아 처음부터 찾아가는 방법으로 만들어진다.
그렇기에 짧은 시간차만 허용했고 INTERVAL 또한 적게 주었다.
'backend > blockchain' 카테고리의 다른 글
| 20231005 블록체인 baseball (1) | 2023.10.05 |
|---|---|
| 20231005 블록체인 (0) | 2023.10.05 |
| 20230912 블록 체인 지갑 (0) | 2023.09.12 |
| 블록체인 블록생성, 검증,테스트 ts (0) | 2023.09.04 |