728x90
중간에 누군가 데이터를 바꿀 수도 있기 때문에 블록이 변조되지 않았는지, 검증이 필요하다.
블록을 검증하는 조건은 아래와 같이 총 3가지인데, 이를 모두 만족해야한다.
1) 새로운 블럭height 값 = 이전 블럭 height 값 + 1 : height가 1 씩 증가
2) 이전 블럭의 hash 값 = 새로운 블럭의 previousHash 값
3) 블럭의 version, merkleRoot, timestamp, height, previousHash 값을 조합해 hash를 생성했을 때, 블럭의 hash와 값과 동일한지 : 같은 데이터기 때문에 hash도 당연히 같아야한다.
1. 타입선언
@types/Failable.d.ts
declare type Result<R> = { isError: false; value: R }
declare type Failure<E> = { isError: true; error: E }
declare type Failable<R, E> = Result<R> | Failure<E>
Failable type은 Result 혹은 Failure 타입을 가지도록 설정해주었다.
이를 결정하는 것은 isError의 값이다.
만약 Failable type의 isError 값이 true라면 Failure 타입이 되며, 반대로 isError 값이 false라면 Result와 타입이 된다.
boolean 값에 따라 타입이 달라지니 실수하지 않도록 조심하기!
2 Block 검증
src/core/blockchain/block.ts
import { SHA256 } from 'crypto-js'
import merkle from 'merkle'
import { BlockHeader } from './blockHeader'
import { BLOCK_GENERATION_INTERVAL, DIFFICULTY_ADJUSTMENT_INTERVAL, GENESIS } from '@core/config'
import hexToBinary from 'hex-to-binary'
/**
* 객체를 만들기 위함.
* constructor() 객체 만들려고
* this = {
* version : 'asdfasf'
* hash : 'asdfasdfasdfasf',
* merkleRoot.:'asdfasdf',
* data : ['asdf','asdfasdf','asfdasdf']
* }
*/
export class Block extends BlockHeader implements IBlock {
public hash: string
public merkleRoot: string
public nonce: number
public difficulty: number
public data: string[]
constructor(_previousBlock: Block, _data: string[], _adjustmentBlock: Block = _previousBlock) {
super(_previousBlock)
const merkleRoot = Block.getMerkleRoot(_data)
this.merkleRoot = merkleRoot
this.hash = Block.createBlockHash(this)
this.nonce = 0
this.difficulty = Block.getDifficulty(this, _adjustmentBlock, _previousBlock)
this.data = _data
}
public static getGENESIS(): Block {
return GENESIS
}
public static getMerkleRoot<T>(_data: T[]): string {
const merkleTree = merkle('sha256').sync(_data)
return merkleTree.root() || '0'.repeat(64)
}
public static createBlockHash(_block: Block): string {
const { version, timestamp, merkleRoot, previousHash, height, difficulty, nonce } = _block
const values: string = `${version}${timestamp}${merkleRoot}${previousHash}${height}${difficulty}${nonce}`
return SHA256(values).toString()
}
//여기부터 검증
static isValidNewBlock(_newBlock: Block, _previousBlock: Block): Failable<Block, string> {
if (_previousBlock.height + 1 !== _newBlock.height) return { isError: true, error: '블록높이가 맞지않습니다.' }
if (_previousBlock.hash !== _newBlock.previousHash)
return { isError: true, error: '이전해시값이 맞지 않습니다.' }
if (Block.createBlockHash(_newBlock) !== _newBlock.hash)
return { isError: true, error: '블록해시가 올바르지 않습니다.' }
return { isError: false, value: _newBlock }
// 세 개의 조건 모두 만족시 Failable<R> 반환
}
}
맨 아래부분 inValidNewBlock~ 코드블럭이 검증 코드이다.
3 테스트 코드
src/core/config.ts
export const GENESIS: IBlock = {
version: '1.0.0',
height: 0,
hash: '0'.repeat(64),
timestamp: 1231006506,
previousHash: '0'.repeat(64),
merkleRoot: '0'.repeat(64),
difficulty: 0,
nonce: 0,
data: ['GENESIS BLOCK'],
}
src/core/blockchain/block.test.ts
import { Block } from '@core/blockchain/block'
import { GENESIS } from '@core/config'
describe('Block 검증', () => {
let newBlock: Block
it('블록생성', () => {
const data = ['Block #2']
// newBlock = new Block(genesisBlock, data)
newBlock = Block.generateBlock(GENESIS, data, GENESIS)
const newBlock2 = new Block(newBlock, data)
// 이전 블록을 바탕으로, 새로운 블록을 생성
})
it('블록검증 테스트', () => {
// height: 10 , height: 9
const isVaildBlock = Block.isValidNewBlock(newBlock, GENESIS)
if (isVaildBlock.isError) {
console.error(isVaildBlock.error)
return expect(true).toBe(false)
}
expect(isVaildBlock.isError).toBe(false)
})
})
728x90
'블록체인' 카테고리의 다른 글
[Typescript] 타입스크립트로 블록체인 P2P 구현해보기(찍먹) (0) | 2022.06.14 |
---|---|
[Typescript] 타입스크립트로 블록체인 마이닝(채굴) 구현하기 (0) | 2022.06.14 |
블록체인 P2P 기술에 대해 알아보자. (0) | 2022.06.14 |
[Typescript] 타입스크립트로 블록체인 블록 구현하기 (0) | 2022.06.09 |
[블록체인] 블록체인 특징, 구성, 블록 만들어보기 (0) | 2022.06.08 |