1. 程式人生 > >通過構建區塊鏈來學習區塊鏈-1-Transaction|Block|POW

通過構建區塊鏈來學習區塊鏈-1-Transaction|Block|POW

原文連結:https://medium.com/@vanflymen/learn-blockchains-by-building-one-117428612f46

  • 交易Transaction
  • 區塊Block
  • 工作量證明

你來這裡是因為,和我一樣,你對加密貨幣的崛起感到興奮。你想知道區塊鏈是如何工作的——它們背後的基本技術。

但理解區塊鏈並不容易——至少對我來說不是。我艱難地瀏覽了密集的視訊,學習了很多的教程,並處理了由於例子太少而產生的放大的挫折感。

我喜歡邊做邊學。如果您也這樣做,在本指南的最後,您將擁有一個功能良好的區塊鏈,並對它們的工作原理有一個堅實的瞭解。

在你開始之前…

請記住,區塊鏈是一個不可變的、連續的記錄鏈,稱為塊

。它們可以包含事務、檔案或任何您喜歡的資料。但重要的是它們是用雜湊連線在一起的。

如果你不確定雜湊是什麼,這裡有一個解釋

  • 這本指南是針對誰的? 您應該能夠輕鬆地閱讀和編寫一些基本的Python,並對HTTP請求的工作原理有一些瞭解,因為我們將通過HTTP與我們的區塊鏈通訊。

  • 我需要什麼? 確保安裝了Python 3.6+(以及pip)。你還需要安裝Flask和wonderful Requests 庫:

pip install Flask==0.12.2 requests==2.18.4

您還需要一個HTTP客戶機,比如Postman 或cURL;但什麼都行。

  • 最終程式碼在哪裡? 這裡提供了
    原始碼

###步驟1:構建一個區塊鏈

開啟您最喜歡的文字編輯器或IDE,我個人喜歡PyCharm。建立一個名為blockchain.py的新檔案。我們只使用一個檔案,但是如果您丟失了,您可以隨時查閱原始碼。

代表一個區塊鏈

我們將建立一個區塊鏈類,該類的建構函式建立一個初始空列表(用於儲存我們的區塊鏈),另一個用於儲存事務。這是我們班的藍圖:

class Blockchain(object):
    def __init__(self):
        self.chain = []
        self.current_transactions = []
        
    def new_block(self):
        # Creates a new Block and adds it to the chain
        pass
    
    def new_transaction(self):
        # Adds a new transaction to the list of transactions
        pass
    
    [@staticmethod](https://my.oschina.net/staticmethod)
    def hash(block):
        # Hashes a Block
        pass

    [@property](https://my.oschina.net/property)
    def last_block(self):
        # Returns the last Block in the chain
        pass

我們的區塊鏈類負責管理鏈。它將儲存事務,並具有一些用於向鏈新增新塊的輔助方法。讓我們開始充實一些方法。

Block是什麼樣子的?

每個塊都有以下內容:

  1. 一個索引
  2. 一個時間戳(Unix時間)
  3. 一個事務列表
  4. 一個證明(稍後將詳細介紹)
  5. 前一個塊的雜湊

下面是單個塊的例子:

block = {
    'index': 1,
    'timestamp': 1506057125.900785,
    'transactions': [
        {
            'sender': "8527147fe1f5426f9dd545de4b27ee00",
            'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
            'amount': 5,
        }
    ],
    'proof': 324984774000,
    'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824”
}

此時,鏈的概念應該很明顯——每個新塊都包含前一個塊的雜湊(Hash)。這是至關重要的,因為它使區塊鏈具有不變性:如果攻擊者破壞了鏈中較早的一個區塊,那麼所有後續的區塊都將包含不正確的雜湊(Hash)。

這說得通嗎?如果沒有,花點時間讓它沉下去——這是區塊鏈背後的核心理念。

將事務新增到塊中

我們需要一種向塊新增事務的方法。我們的new_transaction()方法對此負責,它非常簡單:

class Blockchain(object):
    ...
    
    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block

        :param sender: <str> Address of the Sender
        :param recipient: <str> Address of the Recipient
        :param amount: <int> Amount
        :return: <int> The index of the Block that will hold this transaction
        """

        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })

        return self.last_block['index'] + 1

new_transaction()將一個事務新增到列表後,它返回將事務新增到下一個要挖掘的塊的索引。這將在稍後對提交事務的使用者有用。

建立新的Block

當我們的區塊鏈被例項化時,我們需要用一個genesis塊來播種它——一個沒有前處理的塊。我們還需要向genesis塊新增一個“證明”,這是挖掘(或工作證明)的結果。稍後我們將更多地討論採礦。

除了在建構函式中建立genesis塊,我們還將充實new_block()、new_transaction()和hash()的方法:

import hashlib
import json
from time import time


class Blockchain(object):
    def __init__(self):
        self.current_transactions = []
        self.chain = []

        # Create the genesis block
        self.new_block(previous_hash=1, proof=100)

    def new_block(self, proof, previous_hash=None):
        """
        Create a new Block in the Blockchain

        :param proof: <int> The proof given by the Proof of Work algorithm
        :param previous_hash: (Optional) <str> Hash of previous Block
        :return: <dict> New Block
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

        # Reset the current list of transactions
        self.current_transactions = []

        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block

        :param sender: <str> Address of the Sender
        :param recipient: <str> Address of the Recipient
        :param amount: <int> Amount
        :return: <int> The index of the Block that will hold this transaction
        """
        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })

        return self.last_block['index'] + 1

    [@property](https://my.oschina.net/property)
    def last_block(self):
        return self.chain[-1]

    @staticmethod
    def hash(block):
        """
        Creates a SHA-256 hash of a Block

        :param block: <dict> Block
        :return: <str>
        """

        # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

上面的內容應該是直接了當的—我添加了一些註釋和文件字串來幫助保持清晰。我們幾乎完成了對區塊鏈的表示。但此時,您一定想知道如何建立、鍛造或挖掘新的塊。

工作證明

工作演算法(PoW)的一個證明是如何在區塊鏈上建立或挖掘新的塊。PoW的目標是發現一個可以解決問題的數。這個數字一定很難找到,但是很容易被網路上的任何人驗證——從計算的角度來說。這是工作證明背後的核心思想。

我們將看一個非常簡單的例子來幫助理解這一點。

讓我們決定某個整數x乘以另一個y的雜湊必須以0結尾。雜湊(x * y) = ac23dc…0。對於這個簡化的例子,我們令x = 5。用Python實現:

from hashlib import sha256
x = 5
y = 0  # We don't know what y should be yet...
while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
    y += 1
print(f'The solution is y = {y}’)

解是y = 21。因為,生成的雜湊以0結尾:

hash(5 * 21) = 1253e9373e…5e3600155e860

在比特幣中,工作證明演算法被稱為Hashcash。它和上面的基本例子沒有太大的不同。它是礦工們為了建立一個新的塊而競相求解的演算法。通常,難度由字串中搜索的字元數量決定。然後,這些礦商會因為他們的解決方案而獲得一筆交易中的硬幣作為回報。

網路能夠很容易地驗證他們的解決方案。

實現基本的工作證明

讓我們為區塊鏈實現一個類似的演算法。我們的規則將類似於上面的例子:

找到一個數字p,當它與前一個塊的解進行雜湊時,會產生一個前導4個0的雜湊。

import hashlib
import json

from time import time
from uuid import uuid4


class Blockchain(object):
    ...
        
    def proof_of_work(self, last_proof):
        """
        Simple Proof of Work Algorithm:
         - Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
         - p is the previous proof, and p' is the new proof

        :param last_proof: <int>
        :return: <int>
        """

        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        return proof

    @staticmethod
    def valid_proof(last_proof, proof):
        """
        Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?

        :param last_proof: <int> Previous Proof
        :param proof: <int> Current Proof
        :return: <bool> True if correct, False if not.
        """

        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4] == “0000"

為了調整演算法的難度,可以修改前導零的個數。但是4就足夠了。您將發現,新增一個前導零會大大縮短找到解決方案所需的時間。

我們的類幾乎完成了,我們已經準備好開始使用HTTP請求與它進行互動。

本文由Rebase社群的River翻譯並整理;有問題請加微信syuukawa