코드코코

[블록체인] 블록체인만들기 (2) 블록생성과 블록검증(checkValidBlock.js) 본문

블록체인

[블록체인] 블록체인만들기 (2) 블록생성과 블록검증(checkValidBlock.js)

코드코코 2021. 12. 30. 00:48

사전작업

checkValidBlock.js 파일 생성

touch checkValidBlock.js

 

모듈불러오기

merkle 및 사용자모듈

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

 

블록검증

- 생성된 블럭을 블록체인에 추가하려면 반드시 검증을 거쳐야 한다.

검증해야 할 것

1. 추가하려는 현재의 블록 : 블록 구조가 유효한지

- 타입들이 올바른가
- 인덱스가 올바른가 : 현재 블록의 인덱스가 이전블록의 인덱스보다 1만큼 큰지
- previousHash가 올바른가 (이전 블록값 이용)
- body의 내용이 존재하지 않는가? 👉없으면 안됨
- 암호화가 제대로 되었는가 : 이전 블록의 해시값과 현재 블록의 이전 해시가 같은지

- 데이터 필드로부터 계산한 머클루트와 블록 헤더의 머클루트가 동일한지

2. 전체적인 블록

- genesisblock이 같은가
- Blocks 배열의 각 요소가 1번의 검증 항목들 다 충족하는지

 

검증 과정 구현

추가하려는 현재 블록을 확인하기위해 필요한 함수

isValidBlockStructure()

블록 구조체의 타입을 충족하는지 검증하기 위한 함수

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'
}

추가하려는 현재 블록 검증하기

isValidNewBlock()

타입, 인덱스, 이전블록의 해쉬값, 바디의 내용이 존재하는지, 암호화가 제대로 되었나,머클루트가 잘 되었는지

이 함수는 블록 다른 노드와 블록 하나만 차이나거나, 아니면 블록 전체를 검증할 때 각각 블록들을 검증할 때 쓰이는 함수이다.

function isValidNewBlock(newBlock, previousBlock) {
  if (isValidBlockStructure(newBlock) === false) {
    console.log("Invalid Block Structure");
    return false
  }
  else if (newBlock.header.index !== previousBlock.header.index + 1) {
    console.log("Invaild index");
    return false
  }
  else if (createHash(previousBlock) !== newBlock.header.previousHash) {
    console.log("Invalid previousHash");
    return false
  }
  else if ((newBlock.body.length === 0 && '0'.repeat(64) !== newBlock.header.merkleRoot) ||
    newBlock.body.length !== 0 && (merkle("sha256").sync(newBlock.body).root() !== newBlock.header.merkleRoot)) {
    console.log('Invalid merkleRoot');
    return false;
  }
  return true
}

전체적인 블록을 검증하기 위한 함수

제네시스 블록이 일치하는지, 각각의 블록이 위의 조건을 충족하는지

//체인 단위로 확인
function isValidChain(newBlocks) {
	//제네시스 블럭이 일치하는 지 확인.
	if (JSON.stringify(newBlocks[0]) !== JSON.stringify(Blocks[0])) {
		return false
	}

	var tempBlocks = [newBlocks[0]];

	for (var i = 1; i < newBlocks.length; i++) {
		if (isValidNewBlock(newBlocks[i], tempBlocks[i - 1])) {
			tempBlocks.push(newBlocks[i])
		}
		else {
			return false;
		}
	}
	return true;
}

 

블록추가

검증된 블록을 블록체인에 추가하기

addBlock()

- 새로운 블럭을 추가하는 함수

- 검증받은 블럭만 체인에 추가될 수 있음.

- 지난번에 만든 chainedBlock.js의 addblock()은 전체 흐름 파악용이었으므로 지우고 checkVaildBlcok.js에 새로운 addBlcok()을 작성.

function addBlock(newBlock) {
	if (isValidNewBlock(newBlock, getLastBlock())) {
		Blocks.push(newBlock)
		return true;
	}
	return false;
}

테스트용 코드로 확인해보기

const block = nextBlock(['new Transaction'])
addBlock(block)

console.log(Blocks)

 

모듈내보내기

module.exports 사용

외부 파일에서 사용할 수 있도록 모듈화 시킴

http 서버에서 사용할 addblock 함수를 exports

module.exports = { addBlock }

 

목차

checkValidBlock.js
1	사전작업
1.1	checkValidBlock.js 파일 생성
-	touch checkValidBlock.js
1.2	모듈 불러오기
-	Merkle 및 사용자모듈
2	블록검증
-	생성된 블럭을 블록체인에 추가하려면 반드시 검증을 거쳐야 한다.
2.1	검증해야 할 것 
2.1.1	추가하려는 현재 블록
2.1.1.1	타입들이 올바른가
2.1.1.2	인덱스가 올바른가
2.1.1.3	previousHash가 올바른가 (이전 블록값 이용)
2.1.1.4	body의 내용이 존재하지 않는가? 👉없으면 안됨
2.1.1.5	암호화가 제대로 되었는가 : 이전 블록의 해시값과 현재 블록의 이전 해시가 같은지
2.1.1.6	데이터 필드로부터 계산한 머클루트와 블록 헤더의 머클루트가 동일한지
2.1.2	전체적인 블록
2.1.2.1	제네시스 블록이 같은지
2.1.2.2	Blocks 배열의 각 요소가 1번의 검증 항목들 다 충족하는지
2.2	검증 과정 구현
2.2.1	추가하려는 현재 블록을 확인하기위해 필요한 함수
2.2.1.1	isValidBlockStructure()
	블록 구조체의 타입을 충족하는지 검증하기 위한 함수
2.2.2	추가하려는 현재 블록 검증하기
2.2.2.1	isValidNewBlock()
		타입, 인덱스, 이전블록의 해쉬값, 바디의 내용이 존재하는지, 암호화가 제대로 되었나,머클루트가 잘 되었는지
	이 함수는 블록 다른 노드와 블록 하나만 차이나거나, 아니면 블록 전체를 검증할 때 각각 블록들을 검증할 때 쓰이는 함수이다.
2.2.3	전체적인 블록 검증하기 위한 함수
2.2.3.1	isValidChain()
	제네시스 블록이 일치하는지, 각각의 블록이 위의 조건을 충족하는지
3	블록추가
3.1	검증된 블록을 블록체인에 추가하기
3.1.1	addBlock()
	검증받은 블록만 체인에 추가될 수 있음.
4	모듈내보내기
4.1	Module.export 사용
- 외부 파일에서 사용할 수 있도록 모듈화 시킴
- http 서버에서 사용할 addblock 함수를 exports

전체코드

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

const merkle = require('merkle')
const { nextBlock, getLastBlock, createHash, Blocks } = 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) {
	if (isValidBlockStructure(newBlock) === false) {
		console.log('Invalid Block Structure')
		return false;
	}
	else if (newBlock.header.index !== previousBlock.header.index + 1) {
		console.log('Invalid Index')
		return false;
	}
	else if (createHash(previousBlock) !== newBlock.header.previousHash) {
		console.log('Invalid previousHash')
		return false
	}
	else if ((newBlock.body.length === 0 && ('0'.repeat(64) !== newBlock.header.merkleRoot) ||
		newBlock.body.length !== 0 && (merkle("sha256").sync(newBlock.body).root() !== newBlock.header.merkleRoot))) {
		console.log('Invalid merkleRoot')
		return false;
	}
	return true;
}

//체인 단위로 확인
function isValidChain(newBlocks) {
	//제네시스 블럭이 일치하는 지 확인.
	if (JSON.stringify(newBlocks[0]) !== JSON.stringify(Blocks[0])) {
		return false
	}

	var tempBlocks = [newBlocks[0]];

	for (var i = 1; i < newBlocks.length; i++) {
		if (isValidNewBlock(newBlocks[i], tempBlocks[i - 1])) {
			tempBlocks.push(newBlocks[i])
		}
		else {
			return false;
		}
	}
	return true;
}

function addBlock(newBlock) {
	if (isValidNewBlock(newBlock, getLastBlock())) {
		Blocks.push(newBlock)
		return true;
	}
	return false;
}


const block = nextBlock(['new Transaction'])
addBlock(block)

console.log(Blocks);

module.exports = {
	addBlock
}