본문 바로가기
프로젝트/자바로 만드는 블록체인

[블록체인] 자바로 내 첫 번째 블록체인을 만들어보자 - Part 1. / Java BlockChain / 자바 블록체인

by 으노으뇨 2022. 12. 7.
728x90
반응형
SMALL

안녕하세요~!!! 이번 포스팅으로는 자바로 블록체인을 만들어보고 학습내용을 정리해 보겠습니다!

지금이 튜토리얼 시리즈는 블록체인 기술이라던가 블록체인 개발에 대해서 조금 도움과 이해를 줄 수 있습니다.

이번 포스팅목적은

  • 기본적인 블록체인을 만들어본다.
  • 작업 증명에 대한 마이닝 시스템을 만들어본다.
  • 경이로운 결과

우선 객체 지향 프로그래밍에 대한 기본적인 이해를 가지고 있다고 가정한 뒤에 진행됩니다

여기서의 블록체인은 완벽히 작동하지 않으나 대신 블로체인이 무엇인지 이해하는데 도움을 줄 것입니다.

초기셋팅

  • 자바와  JDK 가 설치 되어야 한다.
  • 이클립스가 설치되어있어야한다. 

이클립스가 아니여도 괜찮습니다! 그러나 나는 이클립스 블랙테마로 진행하겠습니다.

그리고 필요한것은 GSON라이브러리를 의존성 주입해야합니다.

이것은 나중에 JSON으로 출력할때 사용되며, 또 나중에 Peer 2 peer 관련되어서 사용되어집니다.

그러나 다른 대안이 있다면 그걸 사용하셔도 좋습니다.


1. 블록체인 만들기

블록체인은 하나의 체인/블록의 리스트, 체인 입니다.

블록체인의 각 블록은 자체 디지털 서명과 같은 아이덴티티를 가지고 있으며,

이전 블록의 디지털 서명 포함하며, 일부 데이터를 가지고 있으며 이는 데이터는 교환될 수 있습니다.

나카모토가 이 그림을 절대 보지 않았다는 것에 제 손목을 겁니다.

Hash =  Digital Signature

각 블록은 이전 블록의 해쉬값 만 가지고 있는것이 아니라, 각각의 블록 고유 해쉬값도 지니게 된다.

이 해쉬들은 이전 해쉬를 통해서 계산이 되어진다. 만약 이전 블록의 데이터가 변하면 이후 블록의 해쉬값도 변하게 됩니다.

그 결과 모든 블록의 해쉬값들에 영향이 미치게 된다.

import java.util.Date;

public class Block {

	public String hash; //해시값
	public String previousHash; //이전 해시값
	private String data; //간단한 데이터
	private long timeStamp; //기준시 로 이루어진 인트형 시간

	//생성자 코드, 파라미터 2개를 받아오고 타임스탬프는 Date클래스로 받아옴
	public Block(String data,String previousHash ) {
		this.data = data;
		this.previousHash = previousHash;
		this.timeStamp = new Date().getTime();
	}
}

Block 이라는 클래스 하나를 만들어줍니다.

2. SHA256알고리즘 이용하기

다음으로는 디지털 서명을 만드는 소스입니다.

많은 크립토 알고리즘이 있지만 SHA256이 지금 우리가 하는 블록체인 생성 알고리즘에 알맞습니다.

이 SHA256 알고리즘을 우리가 만들 블록에 이용하기위해서 MessageDigest를 사용합니다.

저는 따로 BlockUtils 클래스를 만들어서 해당 기능을 따로 모아서 사용할 클래스로 관리하겠습니다.

Lets type this....

package Java.BlockChain;

import java.security.MessageDigest;

public class BlockUtils
{
	/** 
	 * @apiNote SHA256 알고리즘을 이용해서 해시값을 만들고 해당 값을 return한다.
	 * @param (String) 문자열
	 * @return (String) Hash Value 
	 * */
	public static String applySha256(String input)
	{
		try
		{
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			byte[] hash = digest.digest(input.getBytes("UTF-8"));
			StringBuffer hexString = new StringBuffer();
			for (int i = 0; i < hash.length; i++)
			{
				String hex = Integer.toHexString(0xff & hash[i]);
				if (hex.length() == 1)
				{
					hexString.append('0');
				}
				hexString.append(hex);
			}
			return hexString.toString();
		}
		catch (Exception e)
		{
			// TODO: handle exception
			throw new RuntimeException("예외발생" + e.getMessage());
		}
	}
}

위 함수의 기능은  SHA256알고리즘을 적용시켰며, 하나의 문자열로 리턴을 해준다.

Block 클래스의 해시 값에 해당 계산식을 넣어줍니다.

import java.util.Date;

public class Block {

	private String hash; //해시값
	private String previousHash; //이전 해시값
	private String data; //간단한 데이터
	private long timeStamp; //기준시 로 이루어진 인트형 시간

	//생성자 코드, 파라미터 2개를 받아오고 타임스탬프는 Date클래스로 받아옴
	public Block(String data,String previousHash ) 
   	 {
		this.data = data;
		this.previousHash = previousHash;
		this.timeStamp = new Date().getTime();
        this.hash = calculateHash();//매 호출마다 새로운 해시값을 얻기 위한 메소드
	}
    
   	 public String calculateHash()
	{
		return BlockUtils.applySha256(this.priviousHash + Long.toString(timeStamp) + Integer.toString(nonce) + data);
	}	
	public String getHash()
	{
		return this.hash;
	}
	
	public String getPriviousHash()
	{
		return this.priviousHash;
	}
	
	public String getData()
	{
		return this.data;
	}
}

그럼 위와 같이 블록클래스에 해시값이 매 호출마다 생성되게 됩니다!


3. 테스트

이제 우리가 만든 알고리즘을 테스트 하기위해 메인 메소드가 있는 클래스를 하나 만들어줍니다.

그래서 이렇게 간단하게 만든 소스들이 잘작동하는지 확인해보겠습니다.

블록이름은 우선 uno, dos, tres (라띠나로 1,2,3을 나타냄 - 내 이름 발음과 비슷해서 주로 습니다. ㅎㅎ)

으로 정해서 작성해보겠습니다!!

package Java.BlockChain;

public class JavaChain
{
	public static void main(String[] args) throws JsonProcessingException
	{
		Block unoBlock = new Block("My First Block Chain", "0");
		System.out.println(unoBlock.hash);
		
		Block dosBlock = new Block("My Second Block Chain", unoBlock.hash);
		System.out.println(dosBlock.hash);
		
		Block tresBlock = new Block("My Third Block Chain", dosBlock.hash);
		System.out.println(tresBlock.hash);
	}
}

이렇게 작성하고 한번 실행해 보겠습니다!!!

이는 타임스탬프의 값이 항상 다르기에, 실행하는 그 빠른순간에도 달라지기에 서로 다른 값이 생기게 됩니다.!!!

현재는 블록들이 체인의 형태로 되어있지 않기에 리스트형태로 저장하고

이제 Json 형태로 그것들을 보기위해 Gson을 사용해 보겠습니다!!

package Java.BlockChain;

import java.util.ArrayList;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.gson.GsonBuilder;

public class JavaChain
{
	public static void main(String[] args) throws JsonProcessingException
	{
		ArrayList<Block> blockChains = new ArrayList<>();
		
		Block unoBlock = new Block("My First Block Chain", "0");
		blockChains.add(unoBlock);
		
		Block dosBlock = new Block("My Second Block Chain", unoBlock.getHash());
		blockChains.add(dosBlock);
        
		Block tresBlock = new Block("My Third Block Chain", dosBlock.getHash());
		blockChains.add(tresBlock);
        
		String jsonStr = new GsonBuilder().setPrettyPrinting().create().toJson(blockChains);
		System.out.println(jsonStr);
	}
}

이제 실행을 한다면 Json 형태의 ArrayList가 출력됩니다!!

이제 결과가 블록체인의 형태를 조금씩 비슷하게 보여지는것 같군요!!!


4. 생성된 블록에 대한 무결성 검사

JavaChain클래스에서 이렇게 만들어지는 블록들에 대해서 무결성 검사가 진행되어야합니다.

체인 안에 속해있는 모든 블록들을 루프하며 돌면서 해쉬값을 비교합니다.

 이전 해시값 == 다음 해시값 비교 이후 boolean 형태로 출력

따라서 이 소스는 BlockUtils에 작성하겠습니다. 

	/**
	 * @apiNote 체인 안에 속해있는 모든 블락들을 루프하며 해쉬값 비교. 해쉬 변수가 실제로 계산된 해쉬값과 같은지 그리고 이전
	 *          블락의 해쉬값이 이전 해쉬의 변수와 같은지를 확인.
	 * @param (List)리스트형태의 블록 클래스
	 * @return (boolean)
	 */
	public static boolean inChainValid(List<Block> blockChains)
	{
		for (int i = 1; i < blockChains.size(); i++)
		{
			if (!blockChains.get(i).getHash().equals(blockChains.get(i).calculateHash()))
			{
				System.out.println("Current Hashes not equal");
				return false;
			}
			if (!blockChains.get(i - 1).getHash().equals(blockChains.get(i - 1).getPriviousHash))
			{
				System.out.println("Previous Hashes not equal");
				return false;
			}
		}
		return true;
	}

비트코인의 경우는 네트워크 노드들은 서로 블록체인들을 공유 합니다. 


5. 마이닝을 해보자!

이제 채굴을 위해 proof- of -work 을 수행해야합니다. (작업증명)

Block 클래스에 그러기위해 임시값을 나타내기 위해 None(논스)를 저장할 변수를 만듭니다.

Nonec란? 
논스(nonce)블록체인에서 목표값 이하의 블록 해시를 찾기 위해 임시로 사용하는 숫자이다. 넌스, 또는 난스 또는 임시값이라고 합니다.

난스라고 부르는 int 타입 변수를 calculateHash()안에도 집어 넣습니다. 

또한 필요한성이 많은 mineBlokc()안에도 넣습니다.

maineBlock() 함수를 추가한 Block클래스입니다!

package Java.BlockChain;

import java.util.Date;

class Block
{
	private String hash; // 해시값
	private String priviousHash; // 이전 해시값
	private String data; // 데이터
	private long timeStamp;
	private int nonce;
	
	public Block(String data, String previousHash)
	{
		this.data = data;
		this.priviousHash = previousHash;
		this.timeStamp = new Date().getTime();
		this.hash = calculateHash();
	}
	
	public String calculateHash()
	{
		return BlockUtils.applySha256(this.priviousHash + Long.toString(this.timeStamp) + Integer.toString(this.nonce) + this.data);
	}
	
	public void mineBlock(int difficulty)
	{
		String target = new String(new char[difficulty]).replace('\0', '0');
		String tmpHash = this.hash;
		while (!tmpHash.substring(0, difficulty).equals(target))
		{
			this.nonce++;
			tmpHash = this.calculateHash();
		}
		this.hash = tmpHash;
		System.out.println("Block Mined!!! : " + this.hash);
	}
	
	public String getHash()
	{
		return this.hash;
	}
	
	public String getPriviousHash()
	{
		return this.priviousHash;
	}
	
	public String getData()
	{
		return this.data;
	}
}

maineBlock() 메소드는 int 타입의 어려움단계를 숫자로 받아오는 difficulty를 파라미터로 취합니다.

그리고 이 계산에서 풀어야할 자릿수의 숫자입니다.

아마도 1이나 2와 같이 낮은 자리 숫자는 대부분 컴퓨터에서 바로 처리가 될 수 있습니다.

그렇기 때문에 실험을 위해서 4~6자리 정도의 숫자를 쓰는것이 유용할 것같습니다.

해당 난이도는 상수로 따로 Utils에서 관리할 수 있게끔 합니다.

	/** @apiNote 난이도 어려움 */
	public static int DIFFICULTY_HARD = 6;
	/** @apiNote 난이도 보통 */
	public static int DIFFICULTY_NOMAL = 4;
	/** @apiNote 난이도 쉬움 */
	public static int DIFFICULTY_EASY = 2;

이제 앞서 Utils 파일에 저장한 isChainValid() 함수까지 더해서

채굴하는 클래스를 만들어보겠습니다!!!

package Java.BlockChain;

import java.util.ArrayList;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.gson.GsonBuilder;

public class BlockMining
{
	public static void main(String[] args) throws JsonProcessingException
	{
		ArrayList<Block> blockChains = new ArrayList<>();
		for (int i = 0; i < 4; i++)
		{
			Block block;
			if (i == 0)
			{
				block = new Block("나의 " + i + "번째 블록", "0");
			}
			else
			{
				block = new Block("나의 " + i + "번째 블록", blockChains.get(i - 1).getHash());
			}
			block.mineBlock(BlockUtils.DIFFICULTY_NOMAL);
			blockChains.add(block);
		}
		System.out.println("Bloack is Valid : " + BlockUtils.inChainValid(blockChains));
		String jsonStr = new GsonBuilder().setPrettyPrinting().create().toJson(blockChains);
		System.out.println(jsonStr);
	}
}

총 4개의 블록을 생성하려 하고 루프를 돌면서 생성된 블록이 차곡차곡 add되면서 blockChain에 담기게됩니다.

두근두근 한번 마이닝을 해보겠습니다!!

hashcash, much wow.

이것을 실행하면 다음과 같습니다.

채굴이 완료되었습니다!! 저의 경우 난이도 nomal = 4로 했더니 약 10초? 15초? 정도 소요되었습니다 

아마도 각 난이도를 높힐 수록 엄청 늘어나겠죠?!

만약! 누군가가 우리의 블록체인 시스템에 영향을 미치고 싶을 경우

  • Their blockchain would be invalid.
  • They would not be able to create a longer blockchain.
  • Honest blockchains in your network will have a time advantage on the longest chain.
A tampered blockchain will not be able to catch up with a longer & valid chain. *
*unless they have vastly more computation speed than all other nodes in your network combined. A future quantum computer or something.

이제 우리의 기본 블록체인이 생성되었습니다!

  • 데이터를 저장하는 블록들로 구성되어있다.
  • 체인처럼 연결시켜주는 디지털 서명을 지니고 있다 
  • 새로운 블록을 마이닝을 위해서 작업증명 마이닝을 필요로한다.
  • 블록안의 데이터 변화나 유효성에 대해 체크가 가능하다.

Go on pat yourself on the back.

이제 끝났습니다

는 아니고 2탄이있습니다.

출처는 https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa

 

Creating Your First Blockchain with Java. Part 1.

The aim of this tutorial series, is to help you understand blockchain technology by developing one. If you want to make a real…

medium.com

입니다. 영어 원문보면서 뚝딱거려봤네요. 

다음 포스팅에는 해당 파트 2로 만나뵙겠습니다. !!!!

감사합니다.

그리고 마지막에는 제가 지난 포스팅에서 만든 CPU , 메모미 체커와 쓰레드를  이용해서 실제로 

마이닝이 되는 화면을 함께 보겠습니다!!!

 제가 직접만든 CPU 체커와 블록체인을 구현한 모습입니다!!!

CPU, 메모리 체커는 https://uno-kim.tistory.com/249

 

[리플렉션/AWT] 자바 내 PC의 CPU, 메모리를 실시간으로 확인하는 프로그래밍 / 자바로 간단하게 프

안녕하세요~! !!ㅎㅎㅎ 오늘도 어김없는 자바로 간단하게 프로그램만들어보는 포스팅입니다!! 자바로 간단하게 내 PC의 CPU/메모리를 확인하는 프로그래밍을 만들어보기 이번엔 실시간으로 CPU와

uno-kim.tistory.com

위 포스팅을 통해서 확인하실수 있으십니다!!

제 소스는 깃허브 주소에 올려놨습니다!!!

와서 소스 참고 해주시면 감사하겠습니다.

읽어주셔서 감사합니다~!

https://github.com/uno-km/Study_java/tree/main/src/Java/BlockChain

 

GitHub - uno-km/Study_java

Contribute to uno-km/Study_java development by creating an account on GitHub.

github.com

 

728x90
반응형
LIST

댓글