Blockchain

#5 block 검증

Sila 2022. 6. 12. 20:24

다른 사람이 만든 블럭을 그냥 가져다 쓸 수는 없다.

 

이 블럭이 제대로 된 블럭인지를 먼저 검증하는 과정이 반드시 필요하다.

 

다른 사람이 만든 블럭을 봤을 때 이 블럭이 제대로 된 블럭인가? 를 판별하는 기준은 3가지가 있다.

 

 

a) 새로운 블럭의 height 값이 이전 블럭의 height + 1 의 값을 가지는가?

 

b) 이전 블럭의 hash 값과 새로운 블럭의 previousHash 값이 같은가?

 

c) 새로운 블럭이 가진 data들, 정확히는 version, merkleRoot, timestamp, height, previousHash 값을 조합해

 

내가 hash값을 만들어봤을 때, 이 블럭이 가진 hash 값이 정말 나오는가?

 

 

셋 중 하나라도 만족하지 못하면 이 블럭은 잘못된 블럭이다.

 

이 검증과정은 간단하게 구현할 수 있다.

 

검증하는데 필요한 기준이 되는 '이전 블럭' 과 검증할 '새 블럭'을 가져와 속성을 비교하는 함수를 만들면 된다.

 

이 검증 함수는 Block 자체에 내장되어 있어야 한다.

 

1. ts 문법 - 조건에 따라 다른 형태를 갖는 type

본격적으로 이를 시작하기 전에 ts의 문법을 활용해 상황에 따라 다른 type을 return해주는 type을 하나 만들어주자.

 

/*  @types/Failable.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와 동일한 형태를 가지게 된다.

 

<R>, <E> 는 매개변수로, 우리가 지정해주면 객체 안의 속성값의 데이터 타입을 결정할 수 있다.

 

가령 Failable < Block, string > 처럼 적어주면

 

에러가 있어 Failure 형태를 가질 땐 E가 string,

 

에러가 없어 Result 형태를 가질 땐 R이 Block 타입이 될 것이다. 

 

이를 이용해 블럭 검증 시 에러가 있을 때와 없을때 각각 다른 속성을 가지는 객체를 리턴해줄 수 있다.

 

2. block 검증 함수

/*  src/core/blockchain/block.ts  */

public static isValidNewBlock (_newBlock : Block, _previousBlock : Block ) : Failable <Block, string> {
    // 조건 a 만족 여부 확인
    if(_previousBlock.height + 1 !== _newBlock.hegiht ) {
        return { isError : true, error : 'height value error' }
    }
    // 조건 a 불만족시 Failable<E> 반환
    
    // 조건 a 만족시 조건 b 만족 여부 확인
    if ( _previousBlock.hash !== _newBlock.previousHash ) {
        return { isError : true, error : 'previousHash value Error' }
    }
    // 조건 b 불만족시 Failable<E> 반환
    
    // 조건 b 만족시 조건 c 만족 여부 확인
    if ( Block.createBlockHash(_newBlock) !== _newBlock.hash ) {
        return { isError : true, error : 'hash value error' }
    }
    // 조건 c 불만족
    
    return { isError : false, value : _newBlock }
    // 조건 a,b,c 모두 만족시 Failable<R> 반환
}

 

이를 Block class 내부에 작성해주고 테스트 항목에 검증 코드를 추가해보자.

 

/*  src/core/blockchain/block.test.ts  */

import { Block } from '@core/blockchain/block'

describe('block test', () => {
    let newBlock : Block
    let newBlock2 : Block
    // newBlock, newBlock2 를 전역 변수로 선언
    
    const GENESIS : IBlock = {
        version : '1.0.0',
        height : 0,
        hash : '0'.repeat(64),
        timestamp : 1231006506,
        previousHash : '0'.repeat(64),
        merkleRoot : '0'.repeat(64),
        data : ['genesis Block']
    }
    
    it('블럭 생성', () => {
        const data = ['Blockchain']
        newBlock = new Block ( GENESIS, data )
        newBlock2 = new Block ( newBlock, data )
        // newBlock을 기반으로 newBlock2를 생성
        
        console.log(newBlock)
        console.log(newBlock2)
    })
    
    it('block 검증', () => {
        const isValidBlock = Block.isValidNewBlock (newBlock2, newBlock)
        // 이 변수에는 함수 실행 결과 객체가 들어옴.
        
        if (isValidBlock.isError === true) { // error가 있을 경우
            console.error(isValidBlock.error)
            return expect(true).toBe(false)
            // 반드시 틀리는 모순된 명제를 코드로 넣어 error 유도
        }
        expect(isValidBlock.isError).toBe(false)

 

테스트 해 문제가 없는지 확인한 후,

 

newBlock, newBlock2 를 직접 비교해보자.

'Blockchain' 카테고리의 다른 글

#7 mining ch.1 - 개념  (0) 2022.06.17
#6 chain  (0) 2022.06.12
#4 block 생성  (0) 2022.06.12
#3 typescript - 2  (0) 2022.06.11
#2 typescript  (0) 2022.06.11