블록체인 구현해 보기 (2) - 블록 검증 (feat. JavaScript)

최현석·2021년 12월 30일
0

블록체인

목록 보기
4/5

이전 포스트에서 내가 만든 블록들에 대해서 검증을 해보자.


블록 검증에 필요한 요구사항

  • 블록 구조가 유효한지
  • 재 블록의 인덱스가 이전 블록의 인덱스보다 1만큼 큰지
  • 이전 블록의 해시 값과 현재 블록의 이전 해시가 같은지
  • 데이터 필드로부터 계산한 머클루트와 블록 헤더의 머클루트가 동일한 지

검증 함수 만들기

모듈 선언

// checkValidBlock.js
const merkle = require('merkle')
const {Blocks,getLastBlock,createHash} = require('./chainedBlock')

이전 코드에서 module.exports={Blocks,getLastBlock,createHash, nextBlock} 로 모듈들을 가져와서 선언 해준다.

구조 유효성 검사

  • 먼저 해당 블록의 구조가 유효한지 체크를 해주는 함수를 만들어 준다.
function isValidBlockStructure(block){
	return typeof(block.header.version) === 'string' 
			&& typeof(block.header.index) ==='number'
			&& typeof(block.header.previousHash) ==='string'
			&& typeof(block.header.timestamp) ==='number'
			&& typeof(block.header.merkleRoot) ==='string'
			&& typeof(block.body) ==='object'
}

매개변수로 블록을 받고

해당 블록이 유효하면 true, 유효하지 않다면 false를 반환해준다.

이전 블록과 비교

  • 이전 블록과 비교를 하는 함수를 만들어 준다.
function isValidNewBlock(newBlock, previousBlock){
	// 새로운 블록 구조 유효성 검사를 실패 하였을 때 return false
	if (!isValidBlockStructure(newBlock)){
		console.log('Invalid Block Structure');
		return false;
	}
	// 새로운 블록의 인덱스가 이전 블록의 인덱스보다 1만큼 큰지. 아닐 시 return false
	else if (newBlock.header.index !== previousBlock.header.index +1){
		console.log('Invalid Index');
		return false;
	}
	// 새로운 블록의 이전 해시값이 이전 블록의 해시 값이 아닐 때 return false
	else if (newBlock.header.previousHash !== createHash(previousBlock)){
		console.log('Invalid previousHash');
		return false;
	}
	// 데이터 필드로부터 계산한 머클루트와 블록 헤더의 머클루트가 동일하지 않으면 return false
	else if (
		// 새로운 블록안의 body 데이터가 없을 때 머클 루트 비교
		(newBlock.body.length === 0 && ('0'.repeat(64) !== newBlock.header.merkleRoot))
		||
		// 새로운 블록안의 body 데이터가 있을 때 해당 데이터의 머클 루트 비교
		(newBlock.body.length !== 0 && (merkle('sha256').sync(newBlock.body).root() !== newBlock.header.merkleRoot))
	) {
		console.log('Invalid merkleRoot');
		return false;
	}

	// 해당 블록 검증 완료
	return true
}

매개변수로 newBlock(새로 생성되는 블록)과 previousBlock(이전 블록)을 넣어준다.

해당 함수로 새로 생성되는 블록을 검증 할 수 있다.

add 함수를 만들어서 잘 실행 되는지 실험해보자

function addBlock(newBlock){
  	// addBlock으로 새로운 블록을 받아오고, isValidNewBlock 매개변수로 새로운 블록, 마지막 블록을 넣어준다
  	// 정상 작동 시
	if(isValidNewBlock(newBlock, getLastBlock())){
		console.log('valid block!!')
		Blocks.push(newBlock)
		return true;
	}
  	// 정상 작동 실패 시
	return false
}

// newBlock 생성
const newBlock = nextBlock(['new Transaction']) // 변수로 nextBlock을 써주고 싶은데 이미 함수로 만들어져 있어서 newBlock으로 만듬 ㅠ
addBlock(newBlock)
console.log(newBlock)

검증을 마치고 Blocks배열에 잘 들어간 것을 확인할 수 있다!!


전체코드

const merkle = require('merkle')
const {Blocks,getLastBlock,createHash,nextBlock} = require('./chainedBlock')

function isValidBlockStructure(block){
	return typeof(block.header.version) === 'string' 
			&& typeof(block.header.index) ==='number'
			&& typeof(block.header.previousHash) ==='string'
			&& typeof(block.header.timestamp) ==='number'
			&& typeof(block.header.merkleRoot) ==='string'
			&& typeof(block.body) ==='object'
}

function isValidNewBlock(newBlock, previousBlock){
	// 새로운 블록 구조 유효성 검사를 실패 하였을 때 return false
	if (!isValidBlockStructure(newBlock)){
		console.log('Invalid Block Structure');
		return false;
	}
	// 새로운 블록의 인덱스가 이전 블록의 인덱스보다 1만큼 큰지. 아닐 시 return false
	else if (newBlock.header.index !== previousBlock.header.index +1){
		console.log('Invalid Index');
		return false;
	}
	// 새로운 블록의 이전 해시값이 이전 블록의 해시 값이 아닐 때 return false
	else if (newBlock.header.previousHash !== createHash(previousBlock)){
		console.log('Invalid previousHash');
		return false;
	}
	// 데이터 필드로부터 계산한 머클루트와 블록 헤더의 머클루트가 동일하지 않으면 return false
	else if (
		// 새로운 블록안의 body 데이터가 없을 때 머클 루트 비교
		(newBlock.body.length === 0 && ('0'.repeat(64) !== newBlock.header.merkleRoot))
		||
		// 새로운 블록안의 body 데이터가 있을 때 해당 데이터의 머클 루트 비교
		(newBlock.body.length !== 0 && (merkle('sha256').sync(newBlock.body).root() !== newBlock.header.merkleRoot))
	) {
		console.log('Invalid merkleRoot');
		return false;
	}

	// 해당 블록 검증 완료
	return true
}

function addBlock(newBlock){
	if(isValidNewBlock(newBlock, getLastBlock())){
		console.log('valid block!!')
		Blocks.push(newBlock)
		return true;
	}
	return false
}

const afterBlock = nextBlock(['new Transaction'])
addBlock(afterBlock)
console.log(Blocks)
profile
개발자 꿈나무 https://github.com/Tozinoo

0개의 댓글