JavaScript로 블록체인 만들기 #4

JavaScript 로 블록체인 4단계입니다.

Min Seo Park
CAU_CLink
7 min readJul 8, 2019

--

#4 지갑 구현

이번 4단계에서는 지갑의 구현됨에 따라, wallet.ts 가 추가되었고, blockchain.ts, main.ts, transaction.ts 에 약간의 변화가 생겼다.

<그림 4_1 _ 4단계 결과물 6가지 파일들>

wallet.ts 는 이름에서 볼 수 있듯이 지갑 역할을 하는 파일이다. 개인키와 공개키의 생성 및 저장을 하는 기능과 해당 키로 지갑의 잔고를 알아내는 기능이 구현되어 있다. [1]

wallet.ts 가 추가된 후, blockchain.ts, main.ts, transaction.ts 에도 일정 부분 변화가 생겼다. [2]

이번 4단계에서는

  • 개인키 생성 및 저장
  • 지갑 잔고
  • 거래 생성
  • 지갑 사용을 위한 endpoint

순으로 구현할 예정이다.

#4 지갑

개요

지갑의 목표는 사용자에게 더 추상적인 인터페이스를 제공하는 것이다.

사용자는 다음의 기능들을 사용할 수 있어야 한다.

  • 새 지갑 생성
  • 지갑의 잔고 확인
  • 다른 주소로 코인 전송

사용자는 txIns 나 txOuts 가 어떻게 작동하는지 알지 못하는 상태에서도 위의 기능들은 모두 잘 사용할 수 있어야 한다. 비트코인을 예로 들어보자. 비트코인에서 거래를 할 때는 당신의 주소를 사람들에게 알려주고 주소로 코인을 보내고 받는다. 사용자는 여기까지만 알면 된다.

구현할 전체코드는 여기에서 볼 수 있다.

개인키 생성하고 저장하기

이번 단계에서는 지갑을 만들고 저장하는데 있어서 가장 간단한 방법을 사용할 것이다 : 개인키를 생성하여 node/wallet/private_key 에 파일로 저장할 것이다.

<code 4_1 : 개인키 생성 및 저장>

공개키는 개인키로부터 계산되어 생성된다.

<code 4_2 : 공개키 형성>

지금 생성되는 개인키는 unencrypt 된 형태이다. 일단 지금은 간단한 구현을 하는 과정이므로 추가작업은 하지 않고 넘어가겠지만 unencrypt 된 개인키를 저장하는 것은 상당히 안전하지 않다는 것을 명심해라. 또한 이 단계에서의 지갑은 오직 1개의 개인키만 지원한다, 그렇기에 새로운 공개키를 만들기 위해서는 새로운 지갑을 만들어야 한다.

지갑 잔고

이전 챕터의 내용을 한번 더 보자 : 블록체인에서 만약 당신이 일정량의 코인을 소유한다고 할 때, 실질적으로 당신이 보유하고 있는 것은 코인 그 자체가 아니라 당신의 개인키와 일치하는 사용되지 않은 출력값의 리스트(UTXO List)이다.

그렇기에 주어진 주소의 잔고를 계산하는 것은 꽤나 간단하다 : 해당 주소가 “소유한” 사용되지 않은 출력값을 더하기만 하면 되는 것이다.

<code 4_3 : 지갑 잔고 계산과정>

거래 생성

앞서 언급하였듯이, 코인을 보낼 때, 유저는 거래의 입력값과 출력값의 개념을 굳이 알 필요가 없다. 하지만, 실제 구현을 하는 우리의 입장은 다르다. 만약 A 의 잔고가 50 코인이고 B 에게 10 코인을 보내고 싶은 상황이라면 어떻게 해야할까?

10 코인을 B 의 주소로 보내고 40 코인을 A 에게 다시 보내면 된다. 전체 거래 출력값은 반드시 사용되었어야 했고, 코인에 새로운 출력값을 선정할 때 “나눠지는” 부분이 구현되어야 한다.

아래의 그림처럼 작동하면 될 것이다. (txIns 는 표현하지 않았다) :

<그림4_2 : 거래 생성 과정_1>

조금 더 복잡한 거래 시나리오를 한번 만들어보자 :

  1. C 는 0 코인을 가지고 있다.
  2. 3개의 거래가 발생했다. 이 거래들에서 C는 10, 20, 30 의 코인을 받는다.
  3. C 가 D 에게 55코인을 보내고 싶다. 그렇다면 거래는 어떻게 구성될까?

이런 경우에는, 3개의 output 모두 사용 되어야 하고 D 에게 가는 출력값은 55, C 에게 돌아오는 코인은 5 가 되면 될 것이다.

<그림4_3 : 거래 생성 과정_2>

이제 코드로 한번 짜보자. 먼저 거래 입력값을 만든다. 이를 하기 위해서는, 사용되지 않은 출력값을 검색한다. (모든 출력값은 입력값을 참조하기 때문이다) 이 작업을 출력값들의 합이 보내고자 하는 양만큼 혹은 그 이상이 될 때까지 반복한다.

<code 4_4 : utxo 출력값 검색>

보이는 것처럼, 다시 우리의 주소로 돌아오는 leftOverAmount의 값 역시 계산된다.

먼저, 사용되지 않은 출력값의 리스트로 거래의 txIns 를 만들어 낼 수 있다 :

<code 4_5 : txIns 생성>

다음으로 2개의 거래 txOuts 가 생기게 된다 : 하나의 txOut 은 코인의 수신자를 위한 것이고 나머지 하나는 leftOverAmount용이다. 만약 txIns 가 보내져야하는 양과 정확하게 일치한다면, (leftOverAmount 값이 0이라면) “leftOver” 거래를 생성하지 않는다.

<code 4_6 : txOuts 생성 및 leftOverAmount 생성>

이제 txId 를 계산하고 txIns 를 서명한다 :

<code 4_7 : txId 를 생성, txIns 에서명>

지갑을 사용하기

지갑의 기능성을 위해서 endpoint 를 추가려고 한다.

<code 4_8 : 거래 채굴>

결론

이번 단계에서는 우리는 간단한 거래 생성과 함께 지갑을 구현하였다. 비록 우리가 이번에 구현한 거래 생성 알고리즘은 2개 이상의 출력값을 만들 수 없지만 실제 블록체인은 출력값의 개수와 상관없이 모든 종류의 거래를 지원한다. 50개의 입력값 그리고 5,15, 그리고 30의 출력값을 지닌 거래도 생성할 수 있기는 하다, 하지만 우리가 구현한 결과물에서는 /mineRawBlock인터페이스를 수동적으로 사용하여 생성해야 한다.

또한, 원하는 거래를 블록체인에 포함시키는 유일한 방법은 스스로 채굴하는 것이다. 노드들은 블록체인에 담겨있지 않은 거래에 대한 정보를 서로 교환하지 않는다. 이 부분은 다음 단계 에서 더 보완될 것이다.

구현된 전체코드는 여기서 볼 수 있다.

JavaScript 로 블록체인 만들기 1편 , 2편 , 3편 , 4편 , 5편

[1] : wallet.ts 에는 다음의 것들이 구현되어 있다.

const getPrivateFromWallet
const getPublicFromWallet
const generatePrivateKey
const initWallet
const getBalance
const findTxOutsForAmount
const createTxOuts
const createTransaction

[2] : main.ts , transaction.ts , blockchain.ts 에서는 아래와 같이 변화하였다.

main.ts

import wallet
app.post(‘/mineRawBlock’)
app.post(‘/mineBlock’) 변경
app.get(‘/balance’)
app.post(‘/mineTransaction’)
initWallet();

blockchain.ts

const generateNextBlock
const generatenextBlockWithTransaction
const getAccountBalance

transaction.ts

const validateTxIn 변경

--

--

Min Seo Park
CAU_CLink

Interested in Blockchain, Project Financing and Smart city and Love DJing and EDM