1. 함수
아래와 같이 파이썬으로 구출하는 블록체인 네트워크에서 '암호해시 함수', '거래 내역 저장함수', '채굴 함수' 등을 만들어서 활용해볼 것이다.
import time
import datetime
import hashlib
import json
import requests
# 블록 해시 함수
def hash(block):
# hashes a block
block_string = json.dumps(block, sort_keys=True).encode()
# hash 라이브러리로 sha256 사용
return hashlib.sha256(block_string).hexdigest()
# 거래 내역 저장 함수
def new_transaction(self, sender, recipient, amount):
# Adds a new transaction to the list of transaction
self.current_transaction.append(
{
'sender' : sender, # 송신자
'recipient' : recipient, # 수신자
'amount' : amount, # 금액
'timestamp' : time()
}
)
return self.last_block['index']+1
# 채굴 함수
def mine():
last_block = blockchain.last_block
last_proof = last_block['proof']
proof = blockchain.pow(last_proof) # 여기가 진정한 채굴 단계
blockchain.new_transaction(
sender = mine_owner, # 채굴 시 생성되는 transaction (0 = 운영자)
recipient = node_identifier, # 지갑 주소처럼 사용
amount = nine_profit # coinbase transaction 코인 1개를 줄게!
)
# 등록된 노드들을 함께 업데이트
for node in blockchain.nodes:
header = {'Content-Type' : 'applicaation/json; charset=utf-8'}
data = {
"sender" : mine_order,
"recipient" : node_identifier,
"amount" : mine_profit
}
requests.post("http://" + node + "/transactions/new", headers=headers, data=json.dumps(data))
# Forge the new Block by adding it to the chain
# 전 블록에 대한 hash를 떠 놓고
previous_hash = blockchain.hash(last_block)
# 검증하는 걸 넣어서 블록의 새로 생성
print("MINING STARTED")
block = blockchain.new_block(proof, previous_hash)
print("MINING FINISHED")
# 채굴 성공 후 동료 노드들에게 새로운 블록 정보를 업데이트
# 그렇게 검증도 받아야 하고
#########################
for node in blockchain.nodes:
headers = {'Content-Type' : 'applicaation/json; charset=utf-8'}
data = {
"miner_node" : "http://" + my_ip + ":" + my_port
}
a = requests.get("http://" + node + "/nodes/resolve", headers=headers,data =json.dumps(data))
# print(a.text)
# 이상이 없으면 정상 배출
if "ERROR" not in a.text :
print("다른 노드가 내 블록 검증, 결과 정상!!!!!!")
# block 이 제대로 mine 되었다는 정보를 json 형태로 띄워 줌
response = {
'message' : 'new block found',
'index' : block['index'],
'transactions' : block['transactions'],
'proof' : block['proof'],
'previous_hash' : block['previous_hash']
}
# 이상 발생 시
else:
1==1
print("다른 노드가 내 블록 검증, 에러 발생!!!!!!")
# 문제가 있음 전파
return jsonify(response), 200
2. 객체(Object)
전 포스팅에서 알아보았던 블록체인의 개념들을 바탕으로 간단한 블록체인 객체를 생성해보면 다음과 같다.
<블록체인의 정의>
import datetime
import hashlib
import json
import requests
# 블록체인 객체 선언
class Blockchain(object):
# 블록체인의 기본 특징 선언
def __init__(self):
self.chain = [] # 블록을 연결하는 체인으로
self.current_transaction = [] # 블록 내에 기록되는 transaction
# 거래 내역 저장 함수 : transaction이 추가됨
def new_transaction(self, sender, recipient, amount):
# 현재의 transaction 리스트에 송신자, 수신자 등의 거래 내역을 입력
self.current_transaction.append(
{
'sender' : sender, # 송신자
'recipient' : recipient, # 수신자
'amount' : amount, # 금액
'timestamp' : datetime.datetime.now().timestamp()
}
)
return self.last_block['index']+1
# 새로운 블록을 만드는 함수
def new_block(self, proof, previous_hash=None):
# 지금의 블록에 이어질 새로운 블록 생성
block = {
'index' : len(self.chain)+1, # 지금까지의 체인의 숫자 +1 = 새로운 블록의 인덱스
'timestamp' : datetime.datetime.now().timestamp(), # 지금 시간 넣기
'transactions' : self.current_transaction # 지금까지의 transaction을 넣기
}
self.current_transaction = [] # 새로 블록이 생겼으니 transaction은 다시 초기화
self.chain.append(block) # 기존 체인에 블록을 넣어 연결
return block
@property
def last_block(self):
# 체인의 마지막 블록 가져오기
return self.chain[-1]
블록 객체에 1) 거래 내역을 추가해보고, 2) 체인을 연결해보면 다음과 같다.
<블록체인 객체 선언하고 데이터 확인하기>
import datetime
import hashlib
import json
import requests
# 블록체인 객체 선언
class Blockchain(object):
# 블록체인의 기본 특징 선언
def __init__(self):
self.chain = [] # 블록을 연결하는 체인으로
self.current_transaction = [] # 블록 내에 기록되는 transaction
# 거래 내역 저장 함수 : transaction이 추가됨
def new_transaction(self, sender, recipient, amount):
# 현재의 transaction 리스트에 송신자, 수신자 등의 거래 내역을 입력
self.current_transaction.append(
{
'sender' : sender, # 송신자
'recipient' : recipient, # 수신자
'amount' : amount, # 금액
'timestamp' : datetime.datetime.now().timestamp()
}
)
return self.last_block['index']+1
# 새로운 블록을 만드는 함수
def new_block(self, proof, previous_hash=None):
# 지금의 블록에 이어질 새로운 블록 생성
block = {
'index' : len(self.chain)+1, # 지금까지의 체인의 숫자 +1 = 새로운 블록의 인덱스
'timestamp' : datetime.datetime.now().timestamp(), # 지금 시간 넣기
'transactions' : self.current_transaction # 지금까지의 transaction을 넣기
}
self.current_transaction = [] # 새로 블록이 생겼으니 transaction은 다시 초기화
self.chain.append(block) # 기존 체인에 블록을 넣어 연결
return block
@property
def last_block(self):
# 체인의 마지막 블록 가져오기
return self.chain[-1]
## 블록체인 객체 선언
sample_blockchain = Blockchain()
## 1. 블록에 새로운 블록 만들기
sample_blockchain.new_block(proof = "1")
sample_blockchain.chain
>>> [{'index': 1, 'timestamp': 1726915177.308966, 'transactions': []}]
sample_blockchain.new_block(proof = "1")
sample_blockchain.chain
>>> [{'index': 1, 'timestamp': 1726915398.5879, 'transactions': []}, {'index': 2, 'timestamp': 1726915398.5879, 'transactions': []}]
## 2. 블록에 새로운 거래 내역 입력하기
sample_blockchain.new_transaction(sender = "김민수", recipient="박철수", amount=10)
## 3. 블록에 새로운 블록 만들기
sample_blockchain.new_block(proof = "1")
sample_blockchain.chain
>>>
[{'index': 1, 'timestamp': 1726915507.711371, 'transactions': []},
{'index': 2, 'timestamp': 1726915507.711371, 'transactions': []},
{'index': 3, 'timestamp': 1726915507.711371, 'transactions': [{'sender': '김민수', 'recipient': '박철수', 'amount': 10, 'timestamp': 1726915507.711371}]}]
위의 코드가 앞으로 PoW 블록체인 네트워크를 구축할 때 실제로 활용될 블록체인 객체의 샘플이다.
3. Database(SQLite3)
- csv 양식으로 데이터를 저장할 때 발생하는 문제를 해결하기 위해 데이터베이스를 사용하며, 여기에서는 설치가 간단하고 사용하기 쉬운 SQLite3 패키지를 활용하여 데이터베이스를 구축해보자!
- 실제 블록체인 네트워크에서는 설계자의 선택에 따른 다양한 데이터베이스들이 활용된다.
ex) 비트코인 네트워크는 levelDB, 이더리움은 RocksDB를 데이터베이스로 사용
## SQLite3으로 저장하기
# package 불러오기
import sqlite3
import pandas as pd
# sample.db라는 파일에 connection 만들기(실제 폴더에 sample.db 파일이 생성됨)
conn = sqlite3.connect('sample.db')
# csv 방식과 동일하게 dataframe 생성
df = pd.DataFrame()
df['seller'] = pd.Series(['tom', 'james', 'kaka'])
df['buyer'] = pd.Series(['pepe', 'alex', 'mike'])
df['amount'] = pd.Series([10, 30, 20])
# to_sql 함수를 활용하여 connection(sample.db)의 test_transaction에 저장
df.to_sql('test_transaction', conn)
# 다시 connection(sample.db)의 test_transaction에서 SQL문으로 데이터를 불러옴
df = pd.read_sql_query("SELECT * FROM test_transaction ", conn)
print(df)

데이터베이스에 connection을 만들어 지정한 테이블에 데이터를 저장하고 읽어오는 방식이다.
아래와 같이 데이터베이스 방식은 모든 파일을 로드한 뒤 필요한 데이터만 필터하는 것이 아니라, sql query를 통하여 필요한 데이터를 불러올 수 있어 메모리를 절약할 수 있음!
# connection에 쿼리문(test 테이블에서 seller = ’tom’인 데이터를 불러와라)을 사용해서 데이터 호출
df = pd.read_sql_query("SELECT * FROM test_transaction where seller = 'tom' ", conn)
df

또한 한 개의 db 파일 내에 여러 table을 저장할 수 있어 csv 파일이 수없이 증가하는 문제를 피할 수 있음
기존 csv에서 저장 데이터에 콤마가 포함되어 있을 경우 구분자의 혼란으로 인해 데이터 형식이 붕괴되는 문제도 db를 활용하면 자유로워질 수 있다.
이후 블록체인 네트워크를 구축하며 이 데이터베이스에 블록체인 지갑의 계정 정보를 저장할 예정.
4. 홈페이지 만들기 (Flask)
- 분산원장 기술을 통하여 아무리 철저히 보안을 지킬 수 있다 하더라도, PoW, PoS 등이 발전하여 완전 무결의 새로운 합의 알고리즘이 나타나더라도, 사용자가 유익하고 즐겁게 활용할 수 없다면 의미가 없음
- 결국 블록체인 기술 또한 일반 사용자들이 쉽게 접근하고 활용할 수 있도록 사이트 혹은 애플리케이션이 있어야 함
이를 위해 사이트를 만들고 운영하기 위한 기본적인 지식이 필요하다.
우리가 사용하는 사이트는 크게 2가지의 구성이 결합되어 작동한다.
웹사이트의 사용자가 실제로 클릭하고 데이터를 입력하고 확인하는 front-end(밖 부분)와 back-end(안 부분)가 존재
이번에는 웹사이트의 안 부분인 back-end를 구현하는 파이썬의 패키지인 Flask를 사용해보자.
## Flask를 활용한 웹사이트 제작
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Flask 웹사이트다!'
app.run()


위 코드를 실행시키면 이렇게 컴퓨터가 계속 실행되며 하이퍼링크가 나타나고, 이를 눌러보면 사이트가 구성되는 것을 확인할 수 있다. 해당 사이트에는 방금 파이썬 코드로 입력했던 글이 출력됨

다음으로 html 파일을 불러오는 작업을 진행해보자.
우선 위와 같이 flask 폴더를 만들고 그 안에 다시 한 번 앞에서 구동했던 노트북을 만든 후, template 폴더를 만든다.

그 후 templates 폴더 안에 sample.html이라는 파일을 새로 만들어줌
이 파일에는 간단한 내용을 입력해준 뒤, flask를 통해서 이 html 파일 기반의 사이트를 띄워보자.



코드를 구동시키면 위와 같이 각각의 엔드포인트에 접근했을때 방금 제작했던 파일을 기반으로 하는 사이트가 나오는 것을 확인할 수 있다.
sample.html 내의 텍스트를 수정한 뒤 새로고침 해보면 바로 텍스트가 바뀌는 것도 확인 가능!

이번엔 NAVER 사이트를 그대로 복사해보자.
크롬으로 네이버에 접속한 뒤 개발자 도구에서 모든 html 코드를 복사한다.

이렇게 naver() 함수까지 생성해서 넣은 뒤 실행해보면, 다음과 같이 네이버 홈 화면을 그대로 불러와 보여주는 것을 확인할 수 있다!

이젠 flask를 이용해 back-end 작업을 진행해보자.
먼저 html 파일 backend_sample.html을 만들고 아래의 간단한 내용을 입력하고 기존 html 파일과 같은 디렉터리에 저장

backend_sample.html의 중괄호를 2번 쓴 {{}} 부분에는 back-end, 즉 파이썬에서 작업한 내용이 보여질 예정이다.


여기서 조금 더 응용해보기 위해 다음과 같이 코드에 3+6+100을 입력하여 실제 더한 값인 109가 나오도록 해보았다.


앞으로 파이썬으로 만든 블록체인 네트워크의 산출물들을 front-end 페이지에서 위와 같은 방식으로 보여줄 예정이다.
5. 홈페이지 꾸미기 (JavaScript)
블록체인 네트워크를 구축한 뒤 활용할 지갑을 만들기 위해 자바스크립트가 필요하다.
해당 지갑 사이트를 구축하기 위해서는 두 부분으로 구성된 html 파일을 만들어야 함
1. Form 부분
<form action = "transaction" method = "POST" onsubmit = "toEnabled()">
보내는 사람 지갑 주소 : <input name = "sender" value = "보내는 사람 주소(수정불가)" disabled /> <br>
받을 사람 지갑 주소 : <input type="text" name = "receiver" /> <br>
보낼 코인 : <input type="text" name = "sendable_coin" />
<input type = "submit" value = "코인 보내기" />
</form>
html에서 form은 로그인 화면을 구축할 때 사용된다.
해당 코드는 우리가 보고 있는 화면을 그리고 있으며, 위의 form문 안에는 다음 4가지 정보가 들어갔다.
1. 보내는 사람의 지갑 주소값
- 그러나 보내는 사람의 지갑 주소는 로그인 시점에 이미 정해진 값이기 때문에 바꿀 수 없을 것
- 그래서 값을 입력할 수 없도록 value 값에 '보내는 사람 주소'라는 값이 이미 정해져서 들어가 있다.
- 그렇기에 위 코드에서 실제 창을 보아도 보내는 사람 지갑 주소 부분은 수정할 수 없게 데이터가 고정되어 있다.
2. 받을 사람 지갑 주소
- 받을 사람 지갑 주소는 사용자가 입력할 수 있어야 하기에 input 양식에 type은 text로 선언되었으며 value는 입력되어 있지 않다.
- 덕분에 사용자가 값을 입력할 수 있는 텍스트 박스가 나옴
3. 보낼 코인의 개수
- 받은 사람의 지갑 주소와 마찬가지로 값을 입력할 수 있는 창이 나옴
4. 코인 보내기 버튼
- 위 세 가지와 같은 input이지만 type = "submit"으로 선언되었기에 웹 브라우저에서 버튼 모양을 볼 수 있다.
- value로 선언된 '코인 보내기'값이 버튼 내의 글자로 표시됨
- 제일 윗줄엔 버튼을 submit 했을 때 어떻게 진행되어야 할지 코딩되어 있다.
=> 즉 transaction을 액션으로, POST 방법으로, submit 버튼을 누를 때 toEnabled 함수를 구동시키라는 뜻
2. Script 부분
<script type="text/javascript">
function toEnabled(){
$("input[name=sender]").attr("disabled", false);
}
</script>
- 자바스크립트는 위 코드의 script 태그 사이 부분에 선언되며, 여기에 toEnabled() 함수가 선언되어 있다.
- 이를 해석해보면 input 에서 name이 sender 였던 데이터를 보내라는 뜻
결론적으로 이 javascript.html에서 받을 사람 지갑 주소와 코인 개수를 입력 후 전송 버튼을 누르면 POST 방식으로 toEnabled() 함수를 구동시키며, 이 toEnabled() 함수는 html에서 name 타입이 "sender"인 인풋에 입력된 값을 보내게 됨!
6. 브라우저와 데이터 주고받기(API)
<h1>파이썬 Block Chain Network</h1>
<form action="login" method="POST">
<input type="text" name="wallet_id" placeholder="지갑 ID를 입력해주세요">
<input type="password" name="password" placeholder="비밀번호를 입력해주세요">
<input type="submit" value="로그인" />
</form>
위 코드는 지갑 로그인 화면인 login.html 파일이다.


flask 코드에 로그인 함수를 추가하고 재구동해보면 위와 같은 화면이 뜬다.
여기서 로그인을 클릭해도 반응이 없지만, flask 노트북에서는 새롭게 로그가 기록되는 것을 확인할 수 있다.

이를 활용해서 아래와 같이 코드를 추가해보자.

위와 같이 수정한 뒤 로그인 버튼을 클릭해보면, 이제 로그인 버튼을 누를 때 print 부분이 산출되는 것을 볼 수 있다.
즉 html에서 POST 로 데이터는 보낸 것을 Flask에서 수신한 것!
(웹브라우저와 flask가 연결됨)
그리고 아이디와 패스워드까지 받아보면 로그인 버튼을 클릭했을 때 하단에 id, pw 정보가 print 되는 것을 볼 수 있다.

이제 로그인이 되는 완전한 백엔드를 구현해보면 다음과 같다.
## Flask를 활용한 웹사이트 제작
from flask import Flask
from datetime import datetime
from flask import request
from flask import render_template
app = Flask(__name__)
test_id = "Python"
test_pw = "Blockchain"
@app.route('/')
def index():
return 'Flask 웹사이트다!'
@app.route('/html_sample')
def html_sample():
return render_template('sample.html')
@app.route('/naver')
def naver():
return render_template('naver.html')
@app.route('/backend_sample')
def backend_sample():
num_of_coin = 3+6+100
return render_template('backend_sample.html', backend_result = num_of_coin)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method=='POST':
print("login 버튼을 누름")
input_value = request.form.to_dict(flat=False)
print(input_value)
if(input_value['wallet_id'][0] == test_id) & (input_value['password'][0] == test_pw):
print("로그인 성공")
return "로그인 성공!!"
else:
return render_template('login.html')
return render_template('login.html')
app.run()



'Blockchain' 카테고리의 다른 글
| [Blockchain] Block Wallet 사이트 만들기 (0) | 2024.10.05 |
|---|---|
| [Blockchain] 파이썬으로 만드는 비트코인 (PoW) - 노드 구축 및 운영해보기 (0) | 2024.09.29 |
| [Blockchain] 블록체인이란 무엇일까? - 정의, 구성 요소, 암호 해시, LAYER (1) | 2024.09.20 |