python으로 간단한 블록체인 만들기 (1)

in #kr7 years ago

자바스크립트 버전 을 python으로 포팅한 내용입니다.

블록체인의 가장 기초적인 기능인 블록을 만들고 생성된 블록들을 체인으로 연결하는 법을 구현해보겠습니다.

블록 구성요소를 보면 1. index (블록 인덱스 값) 2.timestamp(블록이 생성된 시간) 3. data (블록에 저장된 데이터, 트랜잭션 등등) 4. previous hash (체인을 구성하기 위한 이 전 블록의 해쉬 값) 5. hash (현재 블록의 해쉬 값) 으로 구성하겠습니다.

class Block():
    def __init__(self, index, timestamp, data):
        self.index = index
        self.timestamp = timestamp
        self.data = data
        self.previousHash = 0
        self.hash = self.calHash()

init 생성자를 통해서 Block 객체가 생성될 때 초기화를 해줍니다. 현재 블록의 해쉬 값은 calHash()함수를 통해서 생성합니다.

import hashlib

class Block():
   def __init__(self, index, timestamp, data):
       self.index = index
       self.timestamp = timestamp
       self.data = data
       self.previousHash = 0
       self.hash = self.calHash()

   def calHash(self):
       return hashlib.sha256(str(self.index).encode() + str(self.data).encode() +
                             str(self.timestamp).encode() + str(self.previousHash).encode()).hexdigest()

calHash함수에서 hash함수로 SHA256을 사용하겠습니다. 파이썬에서는 sha256을 hashlib에서 제공하고 있습니다. hashlib를 import 합니다. sha256에 들어갈 수 있는 데이터 타입은 byte입니다. 그래서 index, timestamp,data, previousHash 를 string으로 변환 후 encode로 한 번 더 변환합니다.
마지막으로 해쉬 값을 16진수로 표현하기 위해서 hexdigest 함수를 사용합니다.

이제 블록체인 클래스를 만들어보겠습니다. 블록체인 클래스에는 블록들이 들어갈 리스트 변수 chain을 만들고 최초 블록을 생성하는 createGenesis함수와 블록을 체인에 추가하는 addBlock함수, 체인이 유효한지 검사하는 isValid 함수로 구성됩니다.

class BlockChain:
    def __init__(self):
        self.chain = []
        self.createGenesis()

    def createGenesis(self):
        self.chain.append(Block(0, time.time(), 'Genesis'))

    def addBlock(self, nBlock):
        nBlock.previousHash = self.chain[len(self.chain)-1].hash
        nBlock.hash = nBlock.calHash()
        self.chain.append(nBlock)

   def isValid(self):
        i = 1
        while(i<len(self.chain)):
            if(self.chain[i].hash != self.chain[i].calHash()):
                return False
            if(self.chain[i].previousHash != self.chain[i-1].hash):
                return False
            i += 1
        return True

Genesis 블록을 만들 때 timestamp 값으로 time.time()을 호출하고 있습니다. 파이썬에서 제공하는 timestamp 라이브러리 입니다. time.time()을 사용하기 위해서 import time 을 추가해야 합니다.

 def createGenesis(self):
        self.chain.append(Block(0, time.time(), 'Genesis'))

생성된 블록을 체인에 추가할 때는 이 전 블록의 해쉬 값과 현 블록의 해쉬 값을 계산해주고 chain에 추가합니다.

 def addBlock(self, newBlock):
        nBlock.previousHash = self.chain[len(self.chain)-1].hash
        nBlock.hash = nBlock.calHash()
        self.chain.append(nBlock)

체인의 유효성 검사는 현재 블록의 해쉬 값과 계산된 해쉬 값의 비교와 현재 블록이 가지고 있는 이전 블록의 해쉬 값과 이전 블록에 저장되어 있는 해쉬 값을 비교를 하면 됩니다

 def isValid(self):
        i = 1
        while(i<len(self.chain)):
            if(self.chain[i].hash != self.chain[i].calHash()):
                return False
            if(self.chain[i].previousHash != self.chain[i-1].hash):
                return False
            i += 1
        return True

총 코드는 아래와 같습니다.

import hashlib
import time
import json

class Block():
    def __init__(self, index, timestamp, data):
        self.index = index
        self.timestamp = timestamp
        self.data = data
        self.previousHash = 0
        self.hash = self.calHash()

    def calHash(self):
        return hashlib.sha256(str(self.index).encode() + str(self.data).encode() +
                              str(self.timestamp).encode() + str(self.previousHash).encode()).hexdigest()

class BlockChain:
    def __init__(self):
        self.chain = []
        self.createGenesis()

    def createGenesis(self):
        self.chain.append(Block(0, time.time(), 'Genesis'))

    def addBlock(self, nBlock):
        nBlock.previousHash = self.chain[len(self.chain)-1].hash
        nBlock.hash = nBlock.calHash()
        self.chain.append(nBlock)

    def isValid(self):
        i = 1
        while(i<len(self.chain)):
            if(self.chain[i].hash != self.chain[i].calHash()):
                return False
            if(self.chain[i].previousHash != self.chain[i-1].hash):
                return False
            i += 1
        return True

import json 부분은 실행해보면서 결과를 보기 편하게 하기 위해 json을 사용하려고 import 했습니다. BlockChain을 객체를 생성하고 프린트 해서 genesis block이 생성됐는지 보겠습니다.

onion = BlockChain()
print(json.dumps(vars(onion.chain[0]), indent=4))
{
    "index": 0,
    "timestamp": 1528433633.7411778,
    "data": "Genesis",
    "previousHash": 0,
    "hash": "08de7c50a83af89e62b66f407083100aae6104c8dd960f165d69ecc8c3a7ea9b"
}

잘 만들어졌습니다. 그러면 새로 블록을 만들어서 추가해보겠습니다.

onion.addBlock(Block(len(onion.chain),time.time(), {"amount":4}))

for block in onion.chain:
    print(json.dumps(vars(block), indent=4))

실행 후에 block이 하나 추가 됐고 previous hash 값이랑 잘 들어갔네요.

{
    "index": 0,
    "timestamp": 1528433734.2385259,
    "data": "Genesis",
    "previousHash": 0,
    "hash": "53aefb7a602912bc49160d34f46e880b433a9209dbe3fd6118802614d91ca9ca"
}
{
    "index": 1,
    "timestamp": 1528433734.2385259,
    "data": {
        "amount": 4
    },
    "previousHash": "53aefb7a602912bc49160d34f46e880b433a9209dbe3fd6118802614d91ca9ca",
    "hash": "85afa45d965a5db0d252a625ff69a13134d001f00b58b0aa4430c8bf8b255874"
}

블록을 두 개 더 만들어 보겠습니다.

onion.addBlock(Block(len(onion.chain),time.time(), {"amount":4}))
onion.addBlock(Block(len(onion.chain),time.time(), {"amount":100}))
onion.addBlock(Block(len(onion.chain),time.time(), {"amount":1000}))

체인이 유효한 지 검사도 해보겠습니다

print('Chain is OK? ', onion.isValid())

변경 한게 없으니 당연히 True가 나오겠죵?

Chain is OK?  True

그럼 중간 block의 데이터를 변경하고 valid를 통과하는 지 보겠습니다.
첫 번째 데이터만 변경해보고 두 번째는 해당 블록의 데이터도 변경하고 해쉬 값도 변경해보겠습니다.

첫 번째 데이터만 변경하게 되면 첫 번째 조건문에서 잡아 내고 해쉬 값까지 변경했을 때는 두 번째 previous hash검사할 때 잡아 내게 됩니다.

onion.chain[2].data = "fake"
print('Chain is OK? ', onion.isValid())
onion.chain[2].hash = onion.chain[2].calHash()
print('Chain is OK? ', onion.isValid())

결과는 아래와 같습니다

Chain is OK?  False
Chain is OK?  False

간단하게 블록체인을 python으로 구현해봤습니다.

스터디하면서 이론으로 본 걸 간단하게라도 구현해보니 이해가 덜 된 부분이 있다는 게 느껴지기도 하네요. 다음에 시간나면 여기에 nonce도 구현하고 transaction 절차와 계좌 생성하는 것도 붙여 봐야겠습니다~

Sort:  

@pangol님 좋은 포스팅 감사합니다! :D
저기 질문이 있는데, 혹시 코딩 왕초보가 입문하기에 좋은 책이나 강좌같은 건 뭐가 있을까요? 혼자 공부를 해보고 싶은데 막막해서요 ㅠㅠ

어떤 걸 만들고 싶으시냐에 따라서 다를 수 있을 것 같아요. 웹 만들고 싶으시면 javascript 언어를 배우시면 되는데 생활코딩이라고 아주 유명한 사이트가 있구요. https://opentutorials.org/course/1
코드아카데미 라고 해서 https://www.codecademy.com/ 이런 사이트도 있습니다. 데이터분석이나 인공지능 하시려면 파이썬을 배우면 도움이 되실 겁니다. 안드로이드 앱을 만들고 싶으신 거면 java 언어 배우시면 됩니당~~~. 책들은 내용이 그리 차이가 나지 않아서 해당 언어로 검색해보시고 제일 많이 팔린 책 보시면 될 것 같아요 :)

너무 막연한 질문이었던 것 같은데, 이렇게 자세히 알려주셔서 감사합니당 :D
요새는 초등학생들도 코딩 교육이 의무화되었다고 하는데, 기초적인 내용도 하나도 모르는 것 같아서 공부해보고 싶다는 막연한 생각이 들다보니 질문 자체도 엄청 막연한 질문이었네요ㅠㅠ 파이썬과 자바스크립트부터 차근차근 알아봐야겠습니당 감사합니다!!

짱짱맨 호출에 출동했습니다!!

오랜만에 뵙네요 감사합니다 :)