在我們開始使用 Python 編程語言構建區塊鏈之前,讓我們回到最開始。2008 年,筆名為中本聰的一位(或多位)作者發布了一份白皮書,描述了純點對點版本的電子現金。除了這種電子現金系統,交易不需要依賴第三方驗證來確保每筆交易的安全性。取而代之的是,每一個事務都會被打上時間戳,然後根據哈希值被哈希到一個正在進行的工作證明鏈中。
因此,什麼是哈希和工作證明?我們將在下面的教程中介紹這些概念,並了解它們如何為加密電子現金系統或加密貨幣奠定基礎。中本聰在他(或她)的論文中描述的電子貨幣的特殊形式成為比特幣,第一種加密貨幣。然而,當試圖使用 Python 構建一個區塊鏈時,這有什麼用呢?
在接下來的教程中,我們也會理解同樣的道理。
理解區塊鏈
比特幣所依賴的系統——一個不斷增長的相互連接的記錄(即區塊)列表——被稱為區塊鏈。比特幣是這一系統的第一個成功應用,在名聲大噪後不久,其他加密貨幣也建立在同樣的信念上。然而,這個系統並不局限於收集財務信息。相反,存儲的數據類型無關緊要,並且獨立於區塊鏈網絡。
從根本上說,存儲在區塊鏈中的數據應該包含以下特徵:
- 不變的
- 分布式的
- 持久(無數據丟失)
- 不可破解
區塊鏈是一個開放源代碼的應用,在成千上萬台計算機之間共享。這些計算機遵循一套規則,以便追蹤從與區塊鏈軟件相關的賬戶發送的資金。為了維護區塊鏈的完整性和交易發生時的網絡安全性,這些質量是強制性的。
每個區塊都是一組數據,例如,“湯姆在 14 日星期二付給哈利 500 美元。”在區塊鏈上,我們可以不用銀行匯款。為了說明這種系統的簡單和優雅,並描述細微差別,我們將了解使用 Python 編程語言創建我們自己的區塊鏈的過程。
對於下面的項目,我們只需要 Python。此外,請記住,我們的區塊鏈將是一個簡化的高級介紹。我們不會建造一個完整的比特幣區塊鏈。相反,我們將創建函數來添加塊、事務和加密,這樣我們的數據就不會被篡改。
我們開始吧。
用 Python 構建區塊鏈
為了更好地理解,我們把建設區塊鏈的過程分成了幾個步驟。這些步驟如下:
步驟 1: 創建區塊鏈類
步驟 2: 編寫一個函數來構建新的塊
步驟 3: 編寫函數來創建新事務並獲取最後一個塊
步驟 4: 編寫一個函數來“哈希”塊
步驟 5: 創建新的區塊鏈並發送一些錢
現在,我們將在以下部分討論這些步驟。
創建區塊鏈類
我們將從導入所需的庫開始。在這種情況下,我們將需要 hashlib 庫來加密,需要 JSON 庫來格式化我們的塊,需要時間庫來存儲每個塊的時間戳。然後我們將創建一個類並初始化以下變量:
- 鏈:這將是一個空列表,我們將向其中添加區塊。確切地說,是“區塊鏈”。
- pendingTransactions :當用戶互相發送硬幣時,他們的交易將位於這個數組中,直到我們批准並將它們插入到一個新的塊中。
- newBlock :這是我們即將定義的一個方法,我們將利用它來包含鏈中的每個塊。
讓我們考慮下面的代碼片段來證明這一點。
示例:
# importing the required libraries
import hashlib
import json
from time import time
# creating the Block_chain class
class Block_chain(object):
def __init__(self):
self.chain = []
self.pendingTransactions = []
self.newBlock(previousHash = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.", the_proof = 100)
說明:
在上面的代碼片段中,我們已經導入了所需的庫,並創建了 Block_chain 類,在這裡我們初始化了前面描述的不同變量。
編寫函數來構造新塊
現在我們已經初始化了一個空鏈,讓我們開始向其中插入塊。然後,我們將使用以下屬性定義 JSON 對象:
- 指數:取區塊鏈的長度,加 1。我們將使用它來引用單個塊,例如,genesis 塊的索引= 1。
- 時間戳:在時間()模塊的幫助下,我們會在塊創建的時候給它打上時間戳。用戶現在可以檢查他們的交易何時在鏈上被確認。
- 交易:任何已經在‘待處理’列表中的交易都將顯示在新的區塊中。
- 證明:這個屬性來自於礦工認為自己找到了有效的‘證明’或者‘現時’。
- previous_hash :最近批准的塊的哈希版本。
一旦我們將上述屬性添加到新塊中,我們將把它們包括在鏈中。最初,我們清空待處理的事務列表,然後將新的塊添加到自身鏈中並返回它。
讓我們使用下面顯示的代碼片段來理解上面的內容。
示例:
# Creating a new block listing key/value pair of
# block information in a JSON object.
# Reset the list of pending transactions &
# append the newest block to the chain.
def newBlock(self, the_proof, previousHash = None):
the_block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.pendingTransactions,
'proof': the_proof,
'previous_hash': previousHash or self.hash(self.chain[-1]),
}
self.pendingTransactions = []
self.chain.append(the_block)
return the_block
說明:
在上面的代碼片段中,我們定義了 newBlock 函數,並包含了前面描述的屬性。我們清空了待處理的事務列表,並向鏈中添加了新的塊。最後,我們歸還了新的街區。
編寫函數來創建新事務並獲取最後一個塊
現在,讓我們將事務列表包含在程序中,因為沒有事務,整個程序毫無意義。因此,讓我們首先定義一個方法,該方法返回最近添加的塊(我們將在一秒鐘內將它用於新索引)。
之後,我們將創建另一個方法來表示新的事務。該方法將由三個最重要的變量組成- 發送方、接收方和金額。如果每筆交易都不包含這些變量,用戶就不能用新生產的加密貨幣消費、賺錢或買東西。請記住,這些交易過於簡化,不能反映真正的加密貨幣中可能存在的東西。
我們將把事務處理對象包含到事務處理對象池中。這些將保持不確定狀態,直到一個新的區塊被開採並加入區塊鏈。為了將來參考,我們將返回新事務將要添加到的塊的索引。
讓我們考慮下面的代碼片段來證明這一點。
示例:
#Searching the blockchain for the most recent block.
@property
def lastBlock(self):
return self.chain[-1]
# Adding a transaction with relevant info to the 'blockpool' - list of pending transactions.
def newTransaction(self, the_sender, the_recipient, the_amount):
the_transaction = {
'sender': the_sender,
'recipient': the_recipient,
'amount': the_amount
}
self.pendingTransactions.append(the_transaction)
return self.lastBlock['index'] + 1
說明:
在上面的代碼片段中,我們將方法定義為 lastBlock() ,它返回最近添加的塊。然後,我們將該函數定義為新交易(),其中我們將 JSON 對象定義為該 _ 交易,並包括發送者、接收者和金額的地址。我們將這個 JSON 對象添加到掛起的事務中,並返回最後一個塊。
編寫一個函數來“哈希”塊
現在,讓我們將密碼學添加到程序中。正如我們所知,比特幣和許多其他區塊鏈貨幣利用 SHA-256 加密哈希函數,該函數接受一些文本字符串(存儲為 Unicode 值)並吐出 64 個字符長的加密字符串。在區塊鏈,我們加密的文本被認為是一個塊。例如,比特幣成因塊的加密字符串或“哈希”如下所示:
FBC 13 b85 C4 ade 52 E2 def 26 EAE 950 F3 b55 df 887 ad 0 F0 FB 5 ebfd 5681 F7 fcb
區塊鏈被認為是防篡改的,因為每個塊都由該塊的先前哈希的副本組成。由於新的哈希是從最後一個塊中派生出來的,我們不能在不改變它前面的每個哈希的情況下改變一個塊的任何方面。
假設有人將比特幣區塊鏈下載到他們的電腦上,並寫道“Satoshi 向 Alex 發送了 723.6 萬枚比特幣!”進入創世紀區塊,並向比特幣網絡廣播了這一消息,並聲稱他是一名秘密億萬富翁。然而,只要任何自尊的礦工將他們當前的區塊鏈副本,尤其是存儲在每個區塊中的哈希值,與他的鏈副本進行比較,他們就會注意到他是一個騙子,拒絕驗證它並讓他離開網絡。
我們將定義接受新塊並將它的鍵/值對變成字符串的方法。然後,我們將該字符串轉換為 Unicode,我們將從 hashlib 庫中將其傳遞到 SHA256 方法中,並根據其返回值創建一個十六進制字符串。然後,我們將返回新的哈希。
讓我們使用下面的代碼片段來理解這一點。
示例:
# receiving one block. Turning it into a string, turning that into
# Unicode (for hashing). Hashing with SHA256 encryption,
# then translating the Unicode into a hexadecimal string.
def hash(self, the_block):
stringObject = json.dumps(the_block, sort_keys = True)
blockString = stringObject.encode()
rawHash = hashlib.sha256(blockString)
hexHash = rawHash.hexdigest()
return hexHash
說明:
在上面的代碼片段中,我們定義了哈希()函數,並接受一個塊,將它們轉換為字符串,然後轉換為 Unicode 進行哈希。然後,我們使用 SHA256() 函數進行加密,然後將 Unicode 轉換為十六進制字符串。
創建新的區塊鏈並發送一些錢
由於我們已經為區塊鏈創建了一個類,並包含了各種方法來構建一個新的塊和一個新的事務,以及一個使用 SHA256 加密來哈希任何塊的自定義方法,讓我們開始構建鏈。
我們將初始化 Block_chain 類的一個實例,並執行一些虛擬事務。確保在我們包含在鏈中的一些塊中列出它們。
讓我們考慮下面的代碼片段來證明這一點。
示例:
block_chain = Block_chain()
transaction1 = block_chain.newTransaction("Satoshi", "Alex", '10 BTC')
transaction2 = block_chain.newTransaction("Alex", "Satoshi", '2 BTC')
transaction3 = block_chain.newTransaction("Satoshi", "James", '10 BTC')
block_chain.newBlock(10123)
transaction4 = block_chain.newTransaction("Alex", "Lucy", '2 BTC')
transaction5 = block_chain.newTransaction("Lucy", "Justin", '1 BTC')
transaction6 = block_chain.newTransaction("Justin", "Alex", '1 BTC')
block_chain.newBlock(10384)
print("Genesis block: ", block_chain.chain)
說明:
我們已經在上面的代碼片段中實例化了 Block_chain() 類。然後,我們執行了一些交易,並為用戶打印了它們。
現在,讓我們看一下使用 Python 構建區塊鏈項目的完整代碼。
完整的項目代碼
檔案:buildingBlockchain.py
# importing the required libraries
import hashlib
import json
from time import time
# creating the Block_chain class
class Block_chain(object):
def __init__(self):
self.chain = []
self.pendingTransactions = []
self.newBlock(previousHash = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.", the_proof = 100)
# Creating a new block listing key/value pairs of
# block information in a JSON object.
# Reset the list of pending transactions &
# append the newest block to the chain.
def newBlock(self, the_proof, previousHash = None):
the_block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.pendingTransactions,
'proof': the_proof,
'previous_hash': previousHash or self.hash(self.chain[-1]),
}
self.pendingTransactions = []
self.chain.append(the_block)
return the_block
#Searching the blockchain for the most recent block.
@property
def lastBlock(self):
return self.chain[-1]
# Adding a transaction with relevant info to the 'blockpool' - list of pending tx's.
def newTransaction(self, the_sender, the_recipient, the_amount):
the_transaction = {
'sender': the_sender,
'recipient': the_recipient,
'amount': the_amount
}
self.pendingTransactions.append(the_transaction)
return self.lastBlock['index'] + 1
# receiving one block. Turning it into a string, turning that into
# Unicode (for hashing). Hashing with SHA256 encryption,
# then translating the Unicode into a hexidecimal string.
def hash(self, the_block):
stringObject = json.dumps(the_block, sort_keys = True)
blockString = stringObject.encode()
rawHash = hashlib.sha256(blockString)
hexHash = rawHash.hexdigest()
return hexHash
block_chain = Block_chain()
transaction1 = block_chain.newTransaction("Satoshi", "Alex", '10 BTC')
transaction2 = block_chain.newTransaction("Alex", "Satoshi", '2 BTC')
transaction3 = block_chain.newTransaction("Satoshi", "James", '10 BTC')
block_chain.newBlock(10123)
transaction4 = block_chain.newTransaction("Alex", "Lucy", '2 BTC')
transaction5 = block_chain.newTransaction("Lucy", "Justin", '1 BTC')
transaction6 = block_chain.newTransaction("Justin", "Alex", '1 BTC')
block_chain.newBlock(10384)
print("Genesis block: ", block_chain.chain)
輸出:
Genesis block: [
{'index': 1,
'timestamp': 1640067926.584454,
'transactions': [],
'proof': 100,
'previous_hash': 'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.'},
{'index': 2,
'timestamp': 1640067926.584454,
'transactions': [
{'sender': 'Satoshi', 'recipient': 'Alex', 'amount': '10 BTC'},
{'sender': 'Alex', 'recipient': 'Satoshi', 'amount': '2 BTC'},
{'sender': 'Satoshi', 'recipient': 'James', 'amount': '10 BTC'}
],
'proof': 10123,
'previous_hash': 'a1b0cf063d43989421eb4b28d9be8f82c2e2e9e40bc9814321e3cbb70b00530a'},
{'index': 3,
'timestamp': 1640067926.584454,
'transactions': [
{'sender': 'Alex', 'recipient': 'Lucy', 'amount': '2 BTC'},
{'sender': 'Lucy', 'recipient': 'Justin', 'amount': '1 BTC'},
{'sender': 'Justin', 'recipient': 'Alex', 'amount': '1 BTC'}
],
'proof': 10384,
'previous_hash': '23699917fdcc013a85bbb5872251768e976bfcc2cd8403565c04970bca24a871'}
]
說明:
在上面的輸出中,我們可以觀察到我們的區塊鏈現在包含三個塊:創世紀塊(索引為 1,沒有事務),此外還有我們自己添加的 2。我們還可以注意到,加密的哈希(從每個前面的塊中導出)和時間戳彼此不匹配。誠然,當我們幾乎同時執行程序和生成塊時,計算機幾乎同時構建每個塊;然而,比特幣塊大約每十分鐘創建一次。
我們有人注意到賬戶餘額了嗎?區塊鏈不是銀行,這裡有一個很好的例子來區分兩者。一個加密貨幣錢包將通過掃描完整的鏈並總結我們收到和花費了多少硬幣來估計餘額。我們不需要依靠銀行來告訴我們賬戶上的金額。我們只信任網絡,而不是一個大公司。是不是很迷人?
總結
在下面的教程中,我們已經成功地構建了一個區塊鏈,我們可以用充滿加密貨幣交易的塊來填充它;然而,這不是一個安全的網絡。首先,我們創建了一個任何時候有人調用 newBlock() 的塊,並且沒有條件。 newBlock() 方法需要一個名為證明的參數;然而,在我們的情況下,這可能是任何事情。它可以是一個數字或一串“你好,世界”,或者字面上的任何東西。
在比特幣的網絡中,一個叫做工作證明的地方有一個共識機制,它說明了實現安全的規則。證據是一個很難找到的隨機數,除非我們有一些專門的高性能機器晝夜不停地工作。
我們還缺少許多其他細節,例如礦工收取的費用、交易計數、公鑰/私鑰、Merkle 樹結構等等。然而,作為區塊鏈中運動線段的基本示例,上面的演練對我們很有幫助。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/254332.html