파이썬으로 블록체인 구축하기: 처음부터 만드는 방법
혹시 비트코인이 블록체인 기술 위에 구축되었다는 사실을 아셨나요? 오늘은 파이썬 프로그래밍 언어를 사용하여 블록체인을 처음부터 구축하는 과정을 살펴보겠습니다.
블록체인이란 무엇일까요?
2008년, 사토시 나카모토라는 익명의 개인 혹은 그룹에 의해 비트코인 백서가 발표되었습니다. 이 백서는 중앙 기관(예: 은행) 없이 거래가 가능한 P2P 전자 화폐를 제안했습니다. 많은 사람이 사토시가 이 논문에서 현재 블록체인으로 알려진 분산 정보 저장 방식을 정의했다는 사실을 간과합니다.
블록체인 기술의 핵심:
간단히 말해서, 블록체인은 분산된 컴퓨터 네트워크를 통해 거래를 저장하는 공유되고 변경 불가능한 디지털 장부입니다. 블록체인은 다음과 같이 두 가지 기본 요소로 나눌 수 있습니다.
- 블록: 거래 데이터를 담는 공간
- 체인: 연결된 레코드들의 집합
즉, 블록체인은 특정 매개변수를 포함한 트랜잭션들을 저장하는 블록들이 연결된 구조입니다.
각 블록은 이전 블록 위에 쌓이며 되돌릴 수 없는 체인을 형성합니다. 즉, 모든 블록은 이전 블록에 종속됩니다. 이 구조는 적절한 권한을 가진 누구나 무결성을 확인할 수 있는 강력하고 변경 불가능한 시스템을 만듭니다.
블록체인은 다음과 같은 흥미로운 기능들을 제공합니다.
- 역사적 불변성
- 정보 영속성
- 저장된 데이터의 오류 없음
오늘날 많은 시스템이 암호화폐, 자산 이전(NFT)뿐만 아니라 곧 투표와 같은 분야에도 블록체인 기술에 의존하고 있습니다.
파이썬으로 구현하는 블록체인이 수천 줄의 복잡한 코드로 이루어진 프로그램일 필요는 없습니다. 핵심은 서로 연결된 트랜잭션 목록입니다.
물론 이 설명은 간략하게 요약된 내용입니다. 더 자세한 설명이 필요하시다면, 블록체인에 대한 초보자 친화적인 가이드를 참조하시기 바랍니다.
그럼 바로 파이썬으로 간단한 블록체인을 만들어 보겠습니다.
파이썬으로 블록체인 구축 시작하기
시작하기 전에 이 튜토리얼에서 다룰 내용을 명확히 하겠습니다.
- 파이썬으로 간단한 블록체인 시스템을 구현합니다.
- 미리 정의된 문자열 형태의 트랜잭션과 함께 블록체인을 사용합니다.
- 블록체인의 불변성을 테스트합니다.
여기서는 JSON 대신 파이썬 리스트를 사용할 것입니다. 이는 프로세스를 단순화하고 블록체인의 핵심 개념에 집중하는 데 도움이 됩니다.
이 튜토리얼을 따라 하려면 다음 항목이 필요합니다.
블록 클래스 만들기
선호하는 코드 편집기를 열고 `main.py` 파일을 만드십시오. 이 파일은 우리가 코드를 작성할 곳입니다.
이제 단방향 암호화 메시지를 생성할 수 있는 모듈인 hashlib를 가져옵니다. 해싱과 같은 암호화 기술은 블록체인이 안전한 거래를 생성하는 데 핵심적인 역할을 합니다.
해시 함수는 입력 데이터(일반적으로 인코딩된 문자열)를 받아 “다이제스트” 또는 “서명”이라고 불리는 고유 식별자를 반환하는 알고리즘입니다. 중요한 점은, 해시 함수를 사용하면 입력의 아주 작은 변화도 결과적으로 완전히 다른 식별자를 생성한다는 것입니다. 이 부분은 앞으로 직접 확인할 수 있습니다.
우선 내장 모듈인 `hashlib`를 가져오기만 하면 됩니다.
# main.py 파일 """ 파이썬으로 만드는 간단한 블록체인 """ import hashlib
이 모듈은 대부분의 해싱 알고리즘을 포함하고 있으며, 여기서 우리는 `hashlib.sha256()` 함수를 사용할 것입니다.
이제 완전히 독창적인 블록체인 이름인 `GeekCoinBlock`을 살펴보겠습니다.
class GeekCoinBlock:
def __init__(self, 이전_블록_해시, 트랜잭션_목록):
self.이전_블록_해시 = 이전_블록_해시
self.트랜잭션_목록 = 트랜잭션_목록
self.블록_데이터 = f"{' - '.join(트랜잭션_목록)} - {이전_블록_해시}"
self.블록_해시 = hashlib.sha256(self.블록_데이터.encode()).hexdigest()
코드가 다소 복잡해 보일 수 있다는 것을 인지하고 있습니다. 다음 섹션에서 각 부분을 자세히 분석해 보겠습니다.
GeekCoinBlock 설명
먼저 특정 속성(attributes)과 동작(methods)을 갖는 객체를 위한 래퍼인 `GeekCoinBlock`이라는 클래스를 만듭니다.
다음으로 `GeekCoinBlock` 객체가 생성될 때마다 호출되는 `__init__` 메소드(생성자라고도 함)를 정의합니다.
이 메소드는 세 가지 매개변수를 가집니다:
- `self` (각 객체의 인스턴스)
- `이전_블록_해시` (이전 블록에 대한 참조)
- `트랜잭션_목록` (현재 블록에 기록된 트랜잭션 목록)
이전 해시 및 트랜잭션 목록을 저장하고, `블록_데이터`라는 인스턴스 변수를 문자열로 생성합니다. 실제 암호화폐에서는 이러한 종류의 데이터를 다른 방식으로 저장하겠지만, 단순화를 위해 모든 데이터 블록을 문자열로 저장합니다.
마지막으로, 다른 블록이 체인을 연결하는 데 사용할 `블록_해시`를 만듭니다. 여기서 `hashlib`가 유용하게 사용됩니다. 사용자 정의 해시 함수를 만드는 대신 미리 만들어진 `sha256`을 사용하여 변경 불가능한 블록을 생성할 수 있습니다.
이 함수는 인코딩된 문자열(또는 바이트)을 매개변수로 받습니다. 이것이 `블록_데이터.encode()` 메소드를 사용하는 이유입니다. 그런 다음 `hexdigest()`를 호출하여 인코딩된 데이터를 16진수 형식으로 반환합니다.
이 모든 내용이 복잡하게 느껴질 수 있으므로 파이썬 쉘에서 `hashlib`를 사용해 보겠습니다.
In [1]: import hashlib In [2]: message = "파이썬은 최고야" In [3]: h1 = hashlib.sha256(message.encode()) In [4]: h1 Out[4]: <sha256 ... object @ 0x7efcd55bfbf0> In [5]: h1.hexdigest() Out[5]: 'a40cf9cca ... 42ab97' In [6]: h2 = hashlib.sha256(b"파이썬은 별로야") In [7]: h2 Out[7]: <sha256 ... object @ 0x7efcd55bfc90> In [8]: h2.hexdigest() Out[8]: 'fefe510a6a ... 97e010c0ea34'
보시다시피, “파이썬은 최고야”에서 “파이썬은 별로야”와 같이 입력을 약간만 변경해도 완전히 다른 해시가 생성되는 것을 알 수 있습니다. 이는 블록체인 무결성의 핵심 요소입니다. 블록체인에 아주 작은 변경 사항만 도입해도 해시가 크게 변경됩니다. 이것이 “블록체인은 손상시킬 수 없다”고 말하는 이유입니다.
블록 클래스 사용
나중에 전체 `Blockchain` 클래스를 만들겠지만, 지금은 `Block` 클래스를 사용하여 블록 체인을 생성해 보겠습니다.
같은 파일에서 변수에 저장된 간단한 문자열로 구성된 몇 가지 트랜잭션을 만듭니다. 예를 들어 다음과 같습니다.
class GeekCoinBlock:
...
t1 = "노아가 마크에게 5 GC를 보냅니다"
t2 = "마크가 제임스에게 2.3 GC를 보냅니다"
t3 = "제임스가 앨리슨에게 4.2 GC를 보냅니다"
t4 = "앨리슨이 노아에게 1.1 GC를 보냅니다"
물론 여기서 GC는 GeekCoin을 의미합니다.
이제 `GeekCoinBlock` 클래스를 사용하여 블록체인의 첫 번째 블록을 만들고 해당 속성을 출력해 보겠습니다. 제네시스 블록(다른 블록보다 먼저 오는 첫 번째 블록)의 `이전_해시` 매개변수는 항상 임의의 문자열 또는 해시(이 경우 “firstblock”)라는 점을 기억하십시오.
block1 = GeekCoinBlock('firstblock', [t1, t2])
print(f"블록 1 데이터: {block1.블록_데이터}")
print(f"블록 1 해시: {block1.블록_해시}")
다음으로 두 번째 블록을 만들고, 첫 번째 블록의 해시를 `이전_해시` 인수로 전달합니다.
block2 = GeekCoinBlock(block1.블록_해시, [t3, t4])
print(f"블록 2 데이터: {block2.블록_데이터}")
print(f"블록 2 해시: {block2.블록_해시}")
이제 이 코드 스니펫을 실행하고 결과를 분석해 보겠습니다. 터미널에서 다음을 입력합니다.
❯ python main.py 블록 1 데이터: 노아가 마크에게 5 GC를 보냅니다 - 마크가 제임스에게 2.3 GC를 보냅니다 - firstblock 블록 1 해시: 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d 블록 2 데이터: 제임스가 앨리슨에게 4.2 GC를 보냅니다 - 앨리슨이 노아에게 1.1 GC를 보냅니다 - 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d 블록 2 해시: 448c4306caf7f6937b0307f92f27fbea3bb73b3470363dee5026a1209dadcfa8
현재는 텍스트와 64자 길이의 해시만 볼 수 있지만, 이것이 블록체인 메커니즘의 핵심입니다.
모든 다른 블록의 기초가 되는 제네시스 블록부터 시작합니다.
누구나 체인의 무결성을 검증할 수 있습니다. 예를 들어, 트랜잭션 내용을 약간 수정하면 다음과 같은 결과가 나타납니다.
t2 = "마크가 제임스에게 2.3 GC를 보냅니다" -> t2 = "마크가 제임스에게 3.2 GC를 보냅니다"
블록 해시가 크게 변경되었음을 확인할 수 있습니다.
블록 1 데이터: 노아가 마크에게 5 GC를 보냅니다 - 마크가 제임스에게 3.2 GC를 보냅니다 - firstblock 블록 1 해시: 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c 블록 2 데이터: 제임스가 앨리슨에게 4.2 GC를 보냅니다 - 앨리슨이 노아에게 1.1 GC를 보냅니다 - 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c 블록 2 해시: 569b977306ce88b53e001dca7ba00c03a51c60d6df4650e7657dcd136f2da0ac
현재 프로젝트는 GitHub 저장소에서 확인할 수 있습니다.
블록체인 코딩
수동으로 코딩한 변수를 기반으로 시스템 무결성을 유지하는 것은 비효율적입니다. 따라서 다른 접근 방식이 필요합니다.
이제 블록들이 있습니다. 이제 이러한 블록들을 블록체인으로 연결하는 클래스를 만들어 보겠습니다.
이전 트랜잭션과 블록 객체를 삭제하고 아래 코드를 사용하여 시작합니다.
# main.py
class Blockchain:
def __init__(self):
self.체인 = []
self.제네시스_블록_생성()
def 제네시스_블록_생성(self):
self.체인.append(GeekCoinBlock("0", ['제네시스 블록']))
def 트랜잭션으로부터_블록_생성(self, 트랜잭션_목록):
이전_블록_해시 = self.마지막_블록.블록_해시
self.체인.append(GeekCoinBlock(이전_블록_해시, 트랜잭션_목록))
def 체인_출력(self):
for i in range(len(self.체인)):
print(f"데이터 {i + 1}: {self.체인[i].블록_데이터}")
print(f"해시 {i + 1}: {self.체인[i].블록_해시}n")
@property
def 마지막_블록(self):
return self.체인[-1]
이 코드는 다시 한번 복잡해 보일 수 있습니다. 각 부분을 분석해 보겠습니다.
- `self.체인` — 모든 블록이 기록되는 목록입니다. 목록 인덱스를 통해 각 블록에 접근할 수 있습니다.
- `제네시스_블록_생성` — 체인에 제네시스 또는 첫 번째 블록을 추가합니다. 이 블록의 이전 해시는 “0”이고 트랜잭션 목록은 단순히 “제네시스 블록”입니다.
- `트랜잭션으로부터_블록_생성` — 트랜잭션 목록만으로 블록을 체인에 추가할 수 있습니다. 거래를 기록할 때마다 수동으로 블록을 생성하는 것은 번거로운 작업입니다.
- `체인_출력` — for 루프를 사용하여 블록체인을 출력합니다.
- `마지막_블록` — 체인의 마지막 요소에 접근할 수 있는 속성입니다. `트랜잭션으로부터_블록_생성` 메소드에서 사용됩니다.
이 블록체인을 테스트해 보겠습니다.
# main.py
import hashlib
class GeekCoinBlock:
...
class Blockchain:
...
t1 = "조지가 조에게 3.1 GC를 보냅니다"
t2 = "조가 아담에게 2.5 GC를 보냅니다"
t3 = "아담이 밥에게 1.2 GC를 보냅니다"
t4 = "밥이 찰리에게 0.5 GC를 보냅니다"
t5 = "찰리가 데이비드에게 0.2 GC를 보냅니다"
t6 = "데이비드가 에릭에게 0.1 GC를 보냅니다"
myblockchain = Blockchain()
myblockchain.트랜잭션으로부터_블록_생성([t1, t2])
myblockchain.트랜잭션으로부터_블록_생성([t3, t4])
myblockchain.트랜잭션으로부터_블록_생성([t5, t6])
myblockchain.체인_출력()
이제 `main.py` 파일을 실행합니다.
데이터 1: 제네시스 블록 - 0 해시 1: 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e 데이터 2: 조지가 조에게 3.1 GC를 보냅니다 - 조가 아담에게 2.5 GC를 보냅니다 - 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e 해시 2: 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5 데이터 3: 아담이 밥에게 1.2 GC를 보냅니다 - 밥이 찰리에게 0.5 GC를 보냅니다 - 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5 해시 3: 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589 데이터 4: 찰리가 데이비드에게 0.2 GC를 보냅니다 - 데이비드가 에릭에게 0.1 GC를 보냅니다 - 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589 해시 4: 869df2f03c9860767d35b30a46233fbeea89a3000ae5019d1491e3829d1ab929
축하합니다! 🙌 여러분은 처음부터 간단한 파이썬 블록체인을 만들었습니다.
이제 게터와 세터를 사용하여 블록체인의 불변성을 강화하고, 작업 증명, 마이닝 또는 비트코인 마이닝 기본 글에서 설명된 기타 개념과 같은 추가 기능을 구현할 수 있습니다.
결론
블록체인은 비트코인, 이더리움 및 기타 모든 암호화폐의 기반이 되는 기술입니다. 이 기사에서는 `sha256`, 클래스, 객체와 같은 해시 알고리즘을 사용하여 파이썬으로 블록체인을 만드는 방법을 배웠습니다.
여러분께서는 이제 마이닝 시스템을 구축하고, Django 또는 Flask와 같은 프레임워크를 사용하여 REST API로 구현하는 과제를 수행해 보실 수 있습니다.
많은 사람이 암호화폐로 돈을 벌고 있습니다. 직접 만들어본다면 무엇을 할 수 있을지 상상해보십시오. 🤑
계속 코딩하세요! 👨💻