Hubeen's Home

안녕하세요. 

저는 공주대학교 컴퓨터공학부 컴퓨터소프트웨어전공 17학번 문승현입니다. 

현재 블록체인 기술에 대해 공부를 하여 공부한 내용을 정리하고자 게시글을 작성하였습니다. 

미리 읽어주시는 분들께 감사하며 잘못된 지식이 있을 경우 마음 편하게 피드백주시면 감사하겠습니다.


g-coin 분석(0) : g-coin 분석(0)


이전 게시글의 분석글을 위의 링크로 보실 수 있습니다.

이제 이전 분석을 이어가보도록 하겠습니다.


분석


남은 blockchain.py, miner.py, node.py, proof.py 는 현재 게시글에서 정리를 이어가도록 하겠습니다.


proof.py

import hashlib

import gcoin.config as cfg


def valid_proof(block, proof=None):
    """ Validates proof

    last digits of hash(previous_block.header, proof)
        == config.PROOF_DIGITS

    Args:
        block (obj):
        proof (int): proof to validate

    Returns:
        bool:
    """
    proof = proof if proof else block.proof

    proof_seed = '{0}{1}'.format(block.header.hash(),
                                 proof).encode()

    proof_hash = hashlib.sha256(proof_seed).hexdigest()

    return proof_hash[:block.difficulty] == cfg.PROOF_DIGITS * block.difficulty


def find_proof(block):
    """proof of work

    Args:
        block (obj):

    Returns:
        int: proof
    """
    proof = 0

    while valid_proof(block, proof) is False:
        proof += 1

    return proof


proof.py는 config.py 파일을 불러옵니다.

그리고 두개의 함수가 있네요.


def valid_proof(block, proof=None): """ Validates proof last digits of hash(previous_block.header, proof) == config.PROOF_DIGITS Args: block (obj): proof (int): proof to validate Returns: bool: """ proof = proof if proof else block.proof proof_seed = '{0}{1}'.format(block.header.hash(), proof).encode() proof_hash = hashlib.sha256(proof_seed).hexdigest() return proof_hash[:block.difficulty] == cfg.PROOF_DIGITS * block.difficulty

valid_proof 함수는 유효한 증명인지 확인하는 함수인 것 같습니다.
두개의 인자를 받는 것을 볼 수 있습니다.

block : object 타입으로 블록을 넘겨받습니다.
proof : int 타입으로 블록의 유효한 proof인지 확인하는 값 같습니다.

proof에는 블록의 proof를 넘겨받았는지 확인을 하여 대입을 하는 것 같습니다.
proo_seed 에는 블록의 헤더 해쉬+넘겨받은 proof 값
proof_hash 는 sha256암호화로 블록해쉬 + proof의 값을 암호화하여 해쉬화하는 것을 볼 수 있습니다.

그 후 proof_hash 와 임의의 값과 비교를 하는 것을 볼 수 있습니다.

config에서 설정한 어려움 값이 크면 클 수록 유효한지 안한지를 찾기가 어려울 것 같아보이네요 ^^


def find_proof(block):
    """proof of work

    Args:
        block (obj):

    Returns:
        int: proof
    """
    proof = 0

    while valid_proof(block, proof) is False:
        proof += 1

    return proof


인자로 넘겨받는 블록을 유요할때까지 계속 while문으로 돌리는 것을 볼 수 있었습니다.

유효한 해쉬값을 찾을때까지 +=1 을 하여 리턴하네요 !


miner.py

import gcoin.config as cfg
import gcoin.proof as proof
from gcoin.transaction import Transaction


class Miner:
    def __init__(self, account_id):
        self.account_id = account_id

    def __call__(self, blockchain):
        # Adding mining rewards
        transaction = Transaction(cfg.GENESIS_ACCOUNT_ID,
                                  self.account_id, cfg.AMOUNT_OF_REWARD)
        blockchain.add_transaction(transaction)

        # Make new block with transactions and hash of last block
        new_block = blockchain.new_block()

        # Proof of Work
        new_proof = proof.find_proof(new_block)

        new_block.proof = new_proof

        blockchain.add_block(new_block)

        return new_block


채굴하는 코드입니다!!!

채굴!!! 가즈아!!!!!!


먼저 3개의 코드를 불러오는 것을 볼 수 있습니다.


config.py, proof.py, transaction.py


그리고 초기화에서 account_id 를 클래스 자신에게 대입을 하네요.


아마도 이 계정은 채굴자의 계정이 아닐까 싶습니다 :D


그리고 채굴의 기여한 내용을 거래 기록에 남기네요.

그리고 추가를 하구요.

그리고 채굴되었다면 새로운 블럭을 생성하여 채굴이 완료되는 것을 볼 수 있습니다.


그 뒤 새로운 블럭에 유효한 증명을 하여 새로운 블럭에 대입하고 블록체인에 추가를 하고 새로운 블럭을 리턴을 해주는 코드네요.


blockchain.py

import gcoin.proof
import gcoin.config as cfg
from gcoin.book import Book
from gcoin.block import Block


class BlockChain:
    def __init__(self, chain=None):
        """init chain with existing chain
        or make this new blockchain

        Args:
            chain: list of dictionary of Block, see load_chain
        """
        self.chain = []
        self.book = Book()
        self.transactions = []

        if chain:
            self.load_chain(chain)
        else:
            self.init_chain()

    def init_chain(self):
        """Make genesis block"""
        genesis_block = Block([], previous_hash=cfg.GENESIS_HASH)

        genesis_proof = gcoin.proof.find_proof(genesis_block)

        genesis_block.proof = genesis_proof

        self.add_block(genesis_block)

    def add_transaction(self, transaction):
        """Add new transaction
        It will only add amount

        Args:
            transaction (obj): Transaction object

        Returns:
            int: index of next block of chain
                return -1 if it's not correct transaction
        """
        if self.book.check_balance(transaction):
            self.transactions.append(transaction)
            return len(self.chain) + 1  # Add this transaction to next block
        else:
            raise Exception('Transaction is wrong.')

    def new_block(self):
        last_block = self.chain[-1]

        block = Block(self.transactions,
                      previous_hash=last_block.hash())

        self.transactions = []

        return block

    def add_block(self, block):
        self.chain.append(block)
        self.book.apply(block.transactions)

    def valid(self):
        """Valid chain"""
        index = 1

        while index < len(self):
            prev_block = self.chain[index-1]
            curr_block = self.chain[index]

            # Check hash with previous hash
            if curr_block.previous_hash != prev_block.hash():
                return False

            # Check proof of current block
            if not gcoin.proof.valid_proof(curr_block):
                return False

            index += 1

        return True

    def load_chain(self, chain):
        """load chain from list of dictionary
        from existing blockchain

        Args:
            chain (list):
                [{
                    transactions: [{
                        sender: 'dsf9s9f0ad'
                        recipient: 'dfsad90fasf'
                        amount: 12
                    }]
                    proof: 318832940000
                    previous_hash: 'fj9afje9ajf9sef0s0f'
                    timestamp: 1506057125.900785
                }]
        """
        for block in chain:
            block = Block.init_from_json(block)
            self.add_block(block)

    def last_block(self):
        return self.chain[-1]

    def dump(self):
        return [block.dump() for block in self.chain]

    def __len__(self):
        return len(self.chain)


이게 바로 제일 중요한 블록체인에 대한 코드가 아닐까 싶습니다.


찬찬히 코드를 살펴보도록 합시다!!!


def __init__(self, chain=None): """init chain with existing chain or make this new blockchain Args: chain: list of dictionary of Block, see load_chain """ self.chain = [] self.book = Book() self.transactions = [] if chain: self.load_chain(chain) else: self.init_chain()

def init_chain(self): """Make genesis block""" genesis_block = Block([], previous_hash=cfg.GENESIS_HASH) genesis_proof = gcoin.proof.find_proof(genesis_block) genesis_block.proof = genesis_proof self.add_block(genesis_block)


먼저 블록체인을 위해 리스트와 통장(?)과 거래 기록을 초기화하는 것을 볼 수 있습니다.

그 후 체인이 있을 경우 load_chain함수로 생성한 체인에 로드하네요.

아닐 경우엔 init_chain으로 체인을 초기화하는 것을 볼 수 있습니다.


블록체인에 첫 블록을 추가하는 부분이네요 ㅎㅎ


def add_transaction(self, transaction):
        """Add new transaction
        It will only add amount

        Args:
            transaction (obj): Transaction object

        Returns:
            int: index of next block of chain
                return -1 if it's not correct transaction
        """
        if self.book.check_balance(transaction):
            self.transactions.append(transaction)
            return len(self.chain) + 1  # Add this transaction to next block
        else:
            raise Exception('Transaction is wrong.')


거래 기록 object를 받네요!


check_balance로 거래기록을 받은 것을 인자로 넘겨주어 제대로된 거래인지 확인을 합니다.

제대로 된 거래일 경우 거래 기록에 추가하고 체인에 대해 길이 +1을 하네요.


def new_block(self): last_block = self.chain[-1] block = Block(self.transactions, previous_hash=last_block.hash()) self.transactions = [] return block def add_block(self, block): self.chain.append(block) self.book.apply(block.transactions)


마지막 블록이라는 변수에 체인의 마지막 블록을 대입하며 블록을 생성하네요!

생성한 블럭은 반환해주네요!


그리고 말그대로 블럭체인에 블럭을 추가하는 코드입니다.

def load_chain(self, chain): """load chain from list of dictionary from existing blockchain Args: chain (list): [{ transactions: [{ sender: 'dsf9s9f0ad' recipient: 'dfsad90fasf' amount: 12 }] proof: 318832940000 previous_hash: 'fj9afje9ajf9sef0s0f' timestamp: 1506057125.900785 }] """ for block in chain: block = Block.init_from_json(block) self.add_block(block)


네 이건 json 데이터를 받아 block 을 초기화하고 블록체인에 추가하네요.

그 외엔 딱히 중요한 내용은 없는 것 같습니다.


node.py

import requests
from uuid import uuid4

from gcoin.blockchain import BlockChain


class Node:
    def __init__(self, id=None):
        self.id = id if id else self._generate_id()
        self.neighbor = set()

    @staticmethod
    def _generate_id():
        return str(uuid4()).replace('-', '')

    def add(self, address):
        self.neighbor.add(address)

    def __len__(self):
        return len(self.neighbor)

    @staticmethod
    def fetch_neighbor_chain(address):
        res = requests.get('{0}/chain'.format(address))
        return res.json()

    def consensus_with_neighbor(self, blockchain):
        """Consensus conflicts with neighbor

        Args:
            blockchain (obj): BlockChain object of mine for consensus

        Returns:
            obj or None:
                None if my blockchain is King
                new BlockChain object if my blockchain is looser
        """
        new_blockchain = None
        max_length = len(blockchain)

        for node in self.neighbor:
            data = self.fetch_neighbor_chain(node)

            if data['length'] > max_length:
                new_blockchain = BlockChain(chain=data['chain'])

                if not new_blockchain.valid():
                    new_blockchain = None
                else:
                    max_length = len(new_blockchain)

        return new_blockchain


네 드디어 마지막 파일입니다!!!!


def fetch_neighbor_chain(address):
        res = requests.get('{0}/chain'.format(address))
        return res.json()

chain에 get 리퀘스트를 쏴서 현재 블록체인들의 json 파일을 리턴해주네요.


def consensus_with_neighbor(self, blockchain):
        """Consensus conflicts with neighbor

        Args:
            blockchain (obj): BlockChain object of mine for consensus

        Returns:
            obj or None:
                None if my blockchain is King
                new BlockChain object if my blockchain is looser
        """
        new_blockchain = None
        max_length = len(blockchain)

        for node in self.neighbor:
            data = self.fetch_neighbor_chain(node)

            if data['length'] > max_length:
                new_blockchain = BlockChain(chain=data['chain'])

                if not new_blockchain.valid():
                    new_blockchain = None
                else:
                    max_length = len(new_blockchain)

        return new_blockchain

블록체인을 인자로 받아 현재 체인에 대해 추가하는 코드 부분입니다.


이로써 모든 파일에 대한 코드를 분석해보았습니다.


다음 게시글에서는 서버에서 실행환경을 구축하여 실제로 동작을 하는지를 확인하도록 하겠습니다.


읽어주셔서 감사합니다.


'0x30 Study > 0x32 Blockchain' 카테고리의 다른 글

g-coin 분석(2)  (2) 2018.03.05
g-coin 분석(1)  (1) 2018.03.03
g-coin 분석(0)  (0) 2018.03.01
BlockChain을 공부하자! (0)  (0) 2018.02.28

댓글 1