brunch

You can make anything
by writing

C.S.Lewis

by Nak Dec 15. 2018

[번역] 자바로 블록체인 만들기 파트 2 - 트랜잭션

우선 이 글은 Medium 에서 발췌해온 것이며, 모든 글의 저작권은 아래 링크에 포함됨을 밝힙니다.


https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce

---------------------------------------------------------------------------------------------------------------------------

이 튜토리얼 시리즈의 목적은 블록체인 기술을 어떻게 개발하는지에 대한 그림을 잡는 법을 익히는 것입니다. 파트1의 경우는 밑의 링크에서 확인할 수 있습니다.


(원본)

ttps://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa

(번역본)

https://brunch.co.kr/@chunja07/41


이 두번째 튜토리얼에서 우리가 해야할 일은 다음과 같습니다.


  간단한 월렛 만들기

 서명된 거래 내역을 블록체인을 사용하여 보내기

 쿨함을느끼기


위에 있는 일련의 과정들을 통해서 우리는 우리만의 크립토 코인을(그와 비슷한) 만들 수 있을 것입니다.!


또한 개발 서비스쪽에 관심이 있다면 : axiomtech.io 로 방문해주세요.


지난 번의 튜토리얼에 이어서 우리는 확인 가능한 기본적인 블록체인을 지니게 되었습니다. 하지만 현재 우리가 지니고 있는 체인은 약간은 쓸데없는 메세지들만을 지니고 있을 뿐입니다. 오늘 우리가 해야할 일은 바로 이러한 데이터들을 거래 내역으로 바꾸는 것입니다(우리의 블록은 다양한 거내 내역을 지니고 있을 수 있습니다.)

또한 이를 통하여 간단한 암호 화폐를 만들어 보도록 하겠습니다. 우리의 새로운 코인을 : "NoobCoin"이라고 부르기로 하죠.


이번 튜토리얼은 당신이 자바 블록 만들기 파트 1을 보았다는 가정하에 이루어집니다. -> 링크

필요 기능: bounceycastleGSon을 필요로 합니다.(클릭시 다운 가능)


1. 월렛 준비하기


암호 화폐상에서 코인의 소유권은 블록체인 상에서의 트랜잭션으로 이루어집니다. 모든 참여자들은 펀드를 받고 보낼 수 있는 하나의 주소를 지니고 있습니다. 월렛의 기본 형태로 월렛은 이러한 주소들을 담을 수 있는데, 이 대부분의 월렛들은 블록체인 하에서 새로운 트랜잭션을 생성할 수 있는 소프트웨어이기도 합니다.


트랜잭션에 대한 설명이 이해가 안가더라도 걱정하지 마세요. 곧 설명이 될겁니다 :)


그럼 Wallet 클래스를 만들어 우리의 public key와 private key를 담아보도록 하죠.


java.security 임포트 하는 것을 잊지 마세요!!


public key와 private key는 무엇을 위해서 만드는 건가요?


'noobcoin' public key는 우리의 주소 역할을 합니다. 이 public key를 대금을 받는 용도로 공유하는 것도 가능합니다. 우리의 private key는 우리의 트랜잭션에 싸인을 하는 기능을 수행합니다. 그 private key의 주인 외에는 아무도 noobcoin을 사용할 수 없도록 하는 것이죠. 그렇기 때문에 사용자는 private key를 비밀스럽게 유지해야 합니다. 우리는 우리의 public key를 트랜잭션을 따라서 보내고, 이 public key는 우리의 시그니쳐가 유효한지 아닌지 여부를 확인할 뿐만 아니라 데이터를 다른 사람이 건드렸는지를 확인합니다.


private key는 다른 사람에 의해서 손상되고 싶지 않은 데이터에 싸인을 하는 역할을 합니다. 그리고 public key는 이 서명을 확인하는 역할을 합니다.


우리의 private key와 public key를 "KeyPair" 안에서 생성시킬 것입니다. 우리의 KeyPairs들을 생성하기 위해서 Elliptic-curve-cryptography를 사용할 것입니다. 우리의 Wallet 클래스에 generateKeyPair() 메소드를 추가하고 생성자에서 부르도록 합시다.


이 메소드에 대해  알아야할 점은 바로 이 메소드가 java.security.KeyPairGenerator를 사용하여 Elliptic Curve KeyPair를 점입니다.

이 메소드들을 통해서 Public 그리고 Private 키들을 생성 및 설정할 수 있습니다.


wallet 클래스에 대한 아웃라인을 잡았으니, 트랜잭션에 대해서 알아보도록 합시다.


2. Transactions & Signatures(트랜잭션&시그니쳐)


각 트랜잭션은 아래에 해당되는 데이터를 지니고 있습니다.

계좌를 보내는 사람의 public key(address)

계좌를 받는 사람의 public key(address)

이체되는 계좌의 수량 혹은 금액

보내는 사람이 실제로 계좌를 가지고 있는지를 증명할 이전 트랜잭션들의 레퍼런스 인풋

트랜잭션에서 그에 해당하는 주소가 받은 금액을 보여주는 아웃풋(추후 트랜잭션에서 인풋값이 되는 값)

암호화된 시그니쳐, 이 암호화된 서명을 통해서 주소의 실제 주인이 트랜잭션을 통해 돈을 보내는지 확인할 수 있습니다. 또한 데이터에 어떤 변화가 생겼는지도 알 수 있습니다.(예를 들면, 제 3자가 보내는 금액을 바꾸는 것을 방지하는 역할)


이제 새로운 트랜잭션 클래스를 만들어 봅시다.

f


또한 TransactioInput 클래스와 TransactionOutput 클래스 역시 만들어 보아야 하는데, 이 두 클래스는 추후에 만들어 보기로 하겠습니다.


Transaction 클래스는 시그니쳐를 만들고, 확인할 수 있는 적절한 메소드를 지니고 있으며, 트랜잭션을 확인해주기도 합니다.


하지만 기다리세요...


Signatures(시그니쳐)의 목적은 무엇이며, 어떻게 작동할까요?


Signatures 이 블락체인에서 두가지 중요한 역할을 수행합니다. 첫번째 역할은 바로 실제 코인의 오너만이 그 코인을 사용할 수 있도록 허락해주는 역할입니다. 두번째 역할은 바로 새로운 블럭이 생성되기 전(시작 지점에서) 이미 접수된 트랜잭션에 대해서 다른 사람들이 수정하지 못하도록 방지하는 것입니다.


the priavte key는 데이터를 서명하는데 사용되고, the public key는 그것의 진위를 확인하는데 쓰입니다.

예를 들어,

밥이라는 사람이 2개의 NoobCoins를  셀리에게 보내고 싶다고 합시다. 그럼 그들의 월렛 소프트웨어는 이 내용에 대한 트랜잭션을 생성하며, miner(블럭을 만드는 주체)에게 다음 블럭에 포함시켜달라고 요청합니다.

miner는 받는 사람을 존이라는 사람으로 하여 2개의 코인을 변경하려는 시도를 하였습니다. 하지만 운이 좋게도 밥은 이미 트랜잭션 데이터를 그의 private key에 서명해놓았기 때문에, 누군가가 만약 트랜잭션 데이터를 밥의 public key를 이용하여 데이터를 변경하고자 한다면 이를 확인할 수 있게 됩니다(다른 사람의 public key는 이 트랜잭션을 확인할 수 있는 길이 없기 때문입니다.)


이전의 코드 블럭에서 우리의 시그니쳐는 바이트의 묶음으로 되어있다는 것을 볼 수 있었습니다. 그러니 시그니쳐를 생성하는 메소드를 만들어 보기로 하죠. 우선 해야할 일은 바로 StringUtill 클래스에 있는 기능들의 도움을 받는 것입니다.


(이 메소드의 내용을 전부 이해하지 못했다고 걱정하지는 마세요. 알아야할 것은 applyECDSASig가 private key, string input을 받고, 서명을 하고, 바이트 배열을 리턴한다는 것. verifyECDSASig는 signature public key, string data를 받고, 그 signature가 유효한지에 대해 true인지 false인를 리턴한다는 점. 그리고 getStringFromKey가 암호화된 string를 어떤 키로부터 리턴한다는 것입니다.)


그럼 이 signature 메소드들을 우리의 Transaction 클래스에서 활용해보도록 하죠. 이는 generateSinature()와 verifySignautre() 메소드의 추가를 통해서 이루어집니다.

실제로 현실에서 사용하고자 한다면 사용되는 인풋/아웃풋 데이터라던가 타임 스탬프 값과 같은 정보의 서명 추가도 가능할 것입니다(현재는 최소한의 것만 서명)

이 서명들은 miner에 의해서 새로운 트랜잭션이 블락에 추가될 때마다 확인될 것입니다.

(블럭 체인의 유효성을 검사할때도, 시그니쳐를 확인할 수 있습니다)


3. 월렛과 시그니쳐 테스트


우리는 이제 거의 절반 정도를 마쳤으니, 테스트를 몇개 해보도록 하죠. NoobCain 클래스에 변수를 몇 개 추가해보고, main 메소드의 내용을 교체해보도록 하겠습니다.

2개의 Wallet을 만듭니다. WalletA와 WalletB를 만든 후 WalletA의 private 및 public 키들을 프린트합니다. 트랜잭션을 생성하고, WalletA의 private key를 사용해서 트랜잭션에 서명을 합니다.

그럼 이제 최종적으로 행운을 빌며 테스트를 해볼 시간이네요.


결과는 이렇게 나와야 합니다.

스스로를 칭찬해 주시기 바랍니다. 이제 우리가 해야할 일은 output 과 input을 생성하고 확인하며, 트랜잭션을 블락체인안에 저장하는 일뿐입니다.


4. Inputs & Outputs 1: 어떻게 암호화폐의 소유권이 결정되는가...


당신이 1 비트코인을 소유학 위해서, 1 비트코인을 받아야 합니다. 장부를 통해 1 비트코인을 당신 이름으로 추가하고, 보낸 이로부터 1 비트코인을 빼는 것이 아니라, 보내는 사람이 1 비트코인을 이전에 받았다는 것을 기록한 후에, 트랜잭션 아웃풋이 1 비토코인이 당신의 주소로 보내졌다는 사실을 보여주도록 만드는 것입니다.

(트랜잭션의 input들은 이전 트랜잭션 output들에 대한 기록들입니다.)


당신의 wallet의 잔액은 당신의 주소에 해당하는 사용되지 않은 모든 트랜잭션 output들입니다.

지금부터 우리는 비트코인의 행적을 추적하고, 사용되지 않은 트랜잭션 output들을 부를 것입니다:UTXO's라고 하도록 하죠.


이제 TransactionInput 클래스를 만들어 보도록 하죠.

(이 클래스는 TransactionOutput들 중에서 아직 사용되지 않은 것들을 기록하는 클래스입니다. TransactionOutputId는 그에 대응하는 TransactionOutput을 찾는데 이용될 것이며, miner가 소유권을 체크하는데 이용될 것입니다.)


TransactionOutputs Class:


Transaction 아웃풋들은 트랜잭션으로부터 각 구성원들에게 보내진 최종 금액을 보여주게 됩니다. 이 정보들은 새로운 트랜잭션에서는 인풋으로써 기록되게 될 것이고, 당신이 보낼 코인이 남아있다는 것을 확인하는 용도로 쓰입니다.


5. Inputs & Outputs 2: 트랜잭션 처리...

체인의 블럭들은 많은 트랙잭션들을 취급합니다. 또한 그 블럭체인들은 아주 아주 길 것이기 때문에, 새로운 트랜잭션을 처리하는데 굉장히 긴 시간이 걸릴 수도 있습니다. 왜냐하면 input들을 찾고 확인해야 하니 말입니다. 

이를 피하기 위해 사용되지 않은 모든 트랜잭션의 추가 컬렉션을 두어 인풋으로 사용되게끔 할 것입니다. NoobCain클래스는 모든 UTXO에 대한 컬렉션을 추가합니다.

이제 본론으로 들어갈 차례입니다.

Transaction 클래스 안에 들어있는 processTransaction 메소드를 boolean타입으로 만들어 이 트랜잭션을 처리함으로써 모든 것을 합쳐보도록 하겠습니다.



다른 기능들을 추가해보는 것도 괜찮을 것이다. 가령 트랜잭션 히스토리를 기록하는 것과 같은 것들 말이다.


6. 블럭에 트랜잭션 집어 넣기:

이제 작동하는 트랜잭션 시스템을 만들었으니, 이 시스템을 우리의 블럭 체인에 적용해 보도록 하죠. 우선 해야할 일은 블럭 체인 안에 들어있는 쓸모없는 데이터들을 트랜잭션의 ArrayList로 교체해야 한다는 것입니다.

하지만 하나의 블럭에는 수천개의 트랜잭션이 있을 수 있으니, 해쉬 계산을 하기에는 너무나 많아보이네요..

이것을 해결하기 위해서는 트랜잭션들의 merkle 트리를 사용해야 합니다.(이 부분에 대해서는 곧 설명을 할 예정입니다.)


이제 helper 메서드를 만들어 StringUtils안에 merkleroot를 발생시켜보도록 하죠.


추후에 실제 merkleroot로 바꾸기는 할테지만, 현재로써는 이것도 잘 작동합니다.

이제 우리의 Block 클래스를 바꿔봅시다.

여기서 확인해야할 점은 바로 우리의 Block 생성자가 업데이트 되었다는 사실입니다. 이는 스트링 형태의 데이터로 더이상 보내야할 필요가 없기 때문입니다. 또한 merkle root를 계산된 calculat hash 메소드에 포함시켰다는 점 또한 눈여겨 볼 점이라고 할 수 있겠네요.


우리의 boolean 형태의 addTransaction 메소드는 트랜잭션들을 추가할 것이고 만약 트랜잭션이 성공적으로 추가가 되었다면 true 값을 반환할 것입니다.


 이제 블럭 체인의 트랜잭션을 만들기 위한 모든 구성 요소들이 완성되었어요!!!


7. 대미의 장식(noobcoin에서 모든 것이 시작되었다는 것을 잊지 말자)


코인을 wallets으로 쌍방향으로 보낼 수 있는 지를 테스트 해 보아야 합니다. 또한 블럭 체인의 유효성 역시 업데이트 해야할 것입니다. 하지만 첫번째로 해야할 일은 바로 새로운 코인을 혼합할 수 있는 방법을 알아내야 합니다.


새로운 코인을 생성하는 방법은 많이 있는데 비트코인의 블럭체인의 예시를 한번 들어보도록 하겠습니다:

miners는 그들 스스로 한개의 트랜잯션을 각 블럭들이 생성될 때마다 보상으로 얻을 수 있습니다. 

하지만 우리는 갖고 싶은 만큼의 코인의 수를 첫번째 블럭에(genesis block) 발행할 수 있도록 할 것입니다. 비트코인과 같이 이 genesis block 직접 하드 코딩하겠습니다.


이제 우리가 가지고 있는 NoobChain 클래스를 필요에 맞게 업데이트 해보도록 합시다.


walletA에 100개의Noobcoin을 발행하는 한개의 Genesis 블럭

트랜잭션을 고려한 체인의 유효성체크 업데이트

잘 작동하고 있는지를 확인하기 위한 테스트 트랜잭션


https://gist.github.com/CryptoKass/a797707cfc87b366d5a5757dc549604a#file-noobchain-java

(역자주: 코드가 너무 길어 가독성을 위해 소스 코드 링크 걸어드립니다)

결과 값은 다음과 같이 나올 것입니다.

Wallets들이 당신의 블럭체인에서 안전하게 코인들을 보낼 수 있게 되었습니다. 단 지갑에 돈이 있을 때에만 가능하겠죠. 이 말은 드디어 당신 스스로의 암호화폐를 가지게 되었다는 것을 의미합니다.


이제 당신만의 블럭체인이 완성되었습니다.


이제 당신만의 블럭체인을 만드는데 성공하였습니다!! 당신의 블럭체인은:


new Wallet() 클래스를 통해서 새로운 wallet들을 만들 수 있습니다

Elliptic-Curve를 이용하여 public 및 private 키를 wallets에게 던져줍니다.

당신이 지니고 있는 자산을 디지털 시그니쳐 알고리즘을 활용하여 안전하게 이동시켜 줍니다

사용자들이 당신의 블럭체인에서 트랜잭션을 만들 수 있도록 합니다. 'Block.addTransaction(walletA.sendFunds( walletB.publicKey, 20));’를 활용할 수 있겠네요.

https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain

위의 깃허브 주소에서 소스 코드를 찾아볼 수 있습니다.

Creating Your First Blockchain with Java. Part 3는 Peer2peer 네트워킹, Consensus 알고리즘, 블럭 스토리지, 그리고 데이터베이스에 대해서 다룰 예정입니다.


(파트3는 아직 글이 나오지 않은 상태입니다. 글쓰는 분이 최근 바쁘신지 한동안 업데이트가 없네요! 업데이트 되는대로 번역해서 올려드리도록 하겠습니다!)


매거진의 이전글 [번역] 자바로 블록체인 만드는 법 파트 1
작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari