一個簡單的區塊鏈貨幣,python實現

風靈使發表於2018-08-13

區塊鏈的特點和定義,有很多資料可以查詢。但對於程式設計師,程式碼對於加深理解有著非常大的作用,以下程式碼為python實現的一個區塊鏈貨幣,用來幫助理解。程式碼中配有註釋,copy下來可以直接run,測試程式碼在最後。

地址

理解前提:理解區塊鏈的“賬本”的比喻,基於區塊鏈的電子貨幣的概念,“挖礦”。


import hashlib
import random
import time

# 區塊鏈中交易
class Transaction:
    def __init__(self, from_addr, to_addr, amount):
        """
        fromAddr: 交易的發起人的地址
        toAdddr: 交易的收款人的地址
        amount: 交易金額
        """
        self.from_addr = from_addr
        self.to_addr = to_addr
        self.amount = amount
    def __str__(self):
        return str(self.from_addr) + " send " + str(self.amount) + " to " + str(self.to_addr)

class Block:
    def __init__(self, transactions, timestamp, data = '', previous_hash = '0', nonce = 0):
        """
        transactions:交易列表,實際應用時並不能這麼傳遞,因為交易的量很很大
        timestamp:時間戳
        data:資料
        nonce:隨機數,使用這個數字的改變來更改block的hash值
        previous_hash:上一個模組的hash值
        hash:模組的hash值
        """
        self.transactions = transactions
        self.timestamp = timestamp
        self.data = data
        self.previous_hash = previous_hash
        self.nonce = nonce
        self.hash = self.calculate_block_hash()

    # 計算hash值,上一個block的hash值也在材料中
    def calculate_block_hash(self):
        combination = str(self.timestamp) + str(self.data) + str(self.previous_hash) + str(self.nonce)        
        for trans in self.transactions:
            combination += str(trans)
        return hashlib.sha256(bytes(combination,'utf-8')).hexdigest()
    # 挖掘,為了限制使用者節點的挖掘能力,增加proof of work機制,增加挖掘的難度,difficulty越大,hash碰撞越難
    def mineblock(self,difficult):
        start = 0
        while [v for v in self.hash[start:difficult]] != ['0' for v in range(start, difficult)]:
        # while [v for v in self.hash[start:difficult]] != ['0' for v in range(start, difficult)]:
            self.nonce += 1
            self.hash = self.calculate_block_hash()
        print("挖到了一個 block,"+self.hash+",difficulty為", difficult)
# 區塊鏈
class BlockChain:
    def __init__(self):
        """
        diffculty:難度
        chain:區塊鏈,這裡用陣列表示
        pending_transactions:等待被挖掘的交易列表
        reward_coin:獎勵金,對記賬使用者的獎勵,即區塊鏈貨幣,設定為一個block獎勵1.2個,
                    單一使用者修改此項並不會生效,因為每個人都有賬本,必須說服多數派,擁有大於百分之50的同意。
        """
        self.difficult = 3
        self.chain = [self.genesis_block()]
        self.pending_transactions = []
        self.reward_coin = 1.2
    # 創世塊
    def genesis_block(self):
        first_transaction = Transaction("24monkey", "24monkey", 50)
        return Block([first_transaction], int(time.time()),"創世模組")
    # 獲得區塊鏈最新的block
    def get_latest_block(self):
        return self.chain[len(self.chain) - 1]
    # 記錄交易
    def transaction_record(self, transaction):
        self.pending_transactions.append(transaction)
    # 對區塊鏈中行為進行交易,mining
    def mine_pending_transactions(self, reward_addr):
        new_block = Block(self.pending_transactions, int(time.time()), )
        new_block.mineblock(self.difficult)
        print("成功記錄一筆交易,挖到了一個block")
        self.chain.append(new_block)
        self.pending_transactions = [Transaction('', reward_addr, self.reward_coin)]
    # 增加block
    def add_block(self, block):
        block.previous_hash = self.get_latest_block().hash
        block.mineblock(self.difficult)
        self.chain.append(block)
    # 獲得一個賬戶的balance
    def get_balance(self, addr):
        balance = 0
        for block in self.chain:
            for transaction in block.transactions:
                if transaction.from_addr == addr:
                    balance -= transaction.amount
                elif transaction.to_addr == addr:
                    balance += transaction.amount
        return balance
    # 賬本是否本篡改,篡改者需要篡改所有的block且說服他人,篡改很困難
    def check_chain_validity(self):
        for i in range(1,len(self.chain)):
            current_block = self.chain[i]
            previous_block = self.chain[i-1]
            if(current_block.hash != current_block.calculate_block_hash()):
                return False
            if(current_block.previous_hash != previous_block.hash):
                return False
        return True
def time_s():
    return int(time.time())


if __name__ == '__main__':
    # 初始化一個區塊鏈
    vin_coin = BlockChain()
    # 兩筆交易
    trans_a = Transaction("shiki_addr", "vincent_addr", 44)
    trans_b = Transaction("vincent_addr", "shiki_addr", 44)
    """
    測試挖礦,proof of work的難度測試
    """
    vin_coin.add_block(Block([trans_a], time_s(), {" reason " : " I owed you"}))
    vin_coin.add_block(Block([trans_b], time_s(), {" reason " : " I gave it back to you cause I love you"}))
    """
    測試篡改資料的測試
    """
    print("vin幣chain合法嗎?", vin_coin.check_chain_validity())
    vin_coin.chain[1].transactions[0].amount = 40
    # 修改一個block後,重新計算這個block的hash,並不能成功
    vin_coin.chain[1].hash = vin_coin.chain[1].calculate_block_hash()
    print("vin幣chain合法嗎?", vin_coin.check_chain_validity())

    """
    測試vin幣獎勵機制
    """
    vin_coin.transaction_record(trans_a)
    vin_coin.transaction_record(trans_b)
    vin_coin.mine_pending_transactions("記錄者1")
    # 由於記錄者1獲得獎勵的事件還沒有入賬,所以查不到
    print("記錄者1的賬戶: ", vin_coin.get_balance("記錄者1"))
    # 記錄者2確認了記錄者1的行為,記錄者1的賬戶餘額不足
    vin_coin.mine_pending_transactions("記錄者2")
print("記錄者1的賬戶: ", vin_coin.get_balance("記錄者1"))

相關文章