深入理解區塊鏈最好的方式莫過於親手搭建一個,在這個過程中理解它背後的邏輯和原理。
接上一篇《 學習區塊鏈的最好方法是構建一個(上) 》
第三步:與我們的區塊鏈交互
你可以使用普通的cURL或Postman工具,通過網絡與我們的API進行交互。
啟動服務器:
1. $ python blockchain.py
2. * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
讓我們嘗試通過向http://localhost:5000/mine發出GET請求來挖掘一個區塊:
UsingPostman to make a GET request
讓我們通過向http://localhost:5000/transactions/new 發出一個POST請求來創建一個新的交易,這個交易包含了交易結構的主體:
UsingPostman to make a POST request
如果你不使用 Postman 工具,同樣可以使用cURL這個工具來實現同樣的目的:
1. $ curl -X POST -H “Content-Type: application/json” -d ‘{
2. “sender”: “d4ee26eee15148ee92c6cd394edd974e”,
3. “recipient”: “someone-other-address”,
4. “amount”: 5
5. }’ “http://localhost:5000/transactions/new”
重啟了我的服務器,並挖掘了兩個區塊,總共給出了3個區塊。 讓我們通過請求http://localhost:5000/chain檢查整個鏈:
1. {
2. “chain”: [
3. {
4. “index”: 1,
5. “previous_hash”: 1,
6. “proof”: 100,
7. “timestamp”: 1506280650.770839,
8. “transactions”: []
9. },
10. {
11. “index”: 2,
12. “previous_hash”: “c099bc…bfb7”,
13. “proof”: 35293,
14. “timestamp”: 1506280664.717925,
15. “transactions”: [
16. {
17. “amount”: 1,
18. “recipient”: “8bbcb347e0634905b0cac7955bae152b”,
19. “sender”: “0”
20. }
21. ]
22. },
23. {
24. “index”: 3,
25. “previous_hash”: “eff91a…10f2”,
26. “proof”: 35089,
27. “timestamp”: 1506280666.1086972,
28. “transactions”: [
29. {
30. “amount”: 1,
31. “recipient”: “8bbcb347e0634905b0cac7955bae152b”,
32. “sender”: “0”
33. }
34. ]
35. }
36. ],
37. “length”: 3
38. }
第四步:共識
這非常酷。 我們有一個基本的 Blockchain 接受交易,它允許我們挖掘新的區塊。 但 Blockchain 的關鍵在於,它們應該是分佈式的。 如果它們是分佈式的,我們如何確保它們都在一條鏈? 這被稱為共識的問題,如果我們想要在我們的網絡中有多個節點,我們就必須實現一個共識的算法。
註冊新節點
在實現共識算法之前,我們需要一種方法讓節點知道網絡上的相鄰節點。 我們網絡上的每個節點都應該保留網絡上其他節點的註冊表。 因此,我們需要更多的端點:
1. /nodes/register 以url的形式接受新的節點列表。
2. /nodes/resolve 來實現我們的共識算法,它可以解決任何衝突——以確保一個節點擁有正確的鏈。
我們需要修改 Blockchain 的構造函數,並提供註冊節點的方法:
1. …
2. from urllib.parse import urlparse
3. …
4.
5.
6. class Blockchain(object):
7. def __init__(self):
8. …
9. self.nodes = set()
10. …
11.
12. def register_node(self, address):
13. “””
14. Add a new node to the list of nodes
15.
16. :param address:
Address of node. Eg. ‘http://192.168.0.5:5000’ 17. :return: None
18. “””
19.
20. parsed_url = urlparse(address)
21. self.nodes.add(parsed_url.netloc)
Amethod for adding neighbouring nodes to our Network
使用set()來保存節點列表。 這是確保新節點的添加具有冪等性的廉價方式,這意味著無論我們添加多少次特定節點,它都只會出現一次。
實現算法的共識
如前所述,當一個節點與另一個節點具有不同鏈時就有了衝突。 為了解決這個問題,我們制定一條規則:最長的並且有效的鏈才是權威的。 換句話說,網絡上最長的鍊是事實上的鏈。 利用該算法,我們在網絡節點之間達成了一致。
1. …
2. import requests
3.
4.
5. class Blockchain(object)
6. …
7.
8. def valid_chain(self, chain):
9. “””
10. Determine if a given blockchain is valid
11.
12. :param chain:
A blockchain
13. :return:
True if valid, False if not 14. “””
15.
16. last_block = chain[0]
17. current_index = 1
18.
19. while current_index
20. block = chain[current_index]
21. print(f'{last_block}’)
22. print(f'{block}’)
23. print(“n———–n”)
24. # Check that the hash of the block is correct
25. if block[‘previous_hash’] != self.hash(last_block):
26. return False
27.
28. # Check that the Proof of Work is correct
29. if not self.valid_proof(last_block[‘proof’], block[‘proof’]):
30. return False
31.
32. last_block = block
33. current_index += 1
34.
35. return True
36.
37. def resolve_conflicts(self):
38. “””
39. This is our Consensus Algorithm, it resolves conflicts
40. by replacing our chain with the longest one in the network.
41.
42. :return:
True if our chain was replaced, False if not 43. “””
44.
45. neighbours = self.nodes
46. new_chain = None
47.
48. # We’re only looking for chains longer than ours
49. max_length = len(self.chain)
50.
51. # Grab and verify the chains from all the nodes in our network
52. for node in neighbours:
53. response = requests.get(f’http://{node}/chain’)
54.
55. if response.status_code == 200:
56. length = response.json()[‘length’]
57. chain = response.json()[‘chain’]
58.
59. # Check if the length is longer and the chain is valid
60. if length > max_length and self.valid_chain(chain):
61. max_length = length
62. new_chain = chain
63.
64. # Replace our chain if we discovered a new, valid chain longer than ours
65. if new_chain:
66. self.chain = new_chain
67. return True
68.
69. return False
第一個方法valid_chain() 負責檢查鍊是否有效,通過循環遍歷每個區塊並驗證哈希和證明。
resolve_conflicts() 是這麼一個方法:它遍歷我們所有的鄰近節點,下載它們的鏈並使用上面的方法驗證它們。 如果一個有效的鏈被發現,它的長度大於我們的,我們就替換掉我們當前所使用的鏈。
讓我們將兩個端點註冊到API中,一個用於添加相鄰節點,另一個用於解決衝突:
1. @app.route(‘/nodes/register’, methods=[‘POST’])
2. def register_nodes():
3. values = request.get_json()
4.
5. nodes = values.get(‘nodes’)
6. if nodes is None:
7. return “Error: Please supply a valid list of nodes”, 400
8.
9. for node in nodes:
10. blockchain.register_node(node)
11.
12. response = {
13. ‘message’: ‘New nodes have been added’,
14. ‘total_nodes’: list(blockchain.nodes),
15. }
16. return jsonify(response), 201
17.
18.
19. @app.route(‘/nodes/resolve’, methods=[‘GET’])
20. def consensus():
21. replaced = blockchain.resolve_conflicts()
22.
23. if replaced:
24. response = {
25. ‘message’: ‘Our chain was replaced’,
26. ‘new_chain’: blockchain.chain
27. }
28. else:
29. response = {
30. ‘message’: ‘Our chain is authoritative’,
31. ‘chain’: blockchain.chain
32. }
33.
34. return jsonify(response), 200
此時,你可以使用不同的機器,並在網絡上創建不同的節點。 或者在同一台機器上使用不同的端口來啟動進程。 我在我的機器上的另一個端口上啟動了另一個節點,並將它註冊到我當前的節點上。 因此,我有兩個節點: http://localhost:5000 和 http://localhost:5001 。
Registeringa new Node
然後我在節點2上挖掘了一些新的區塊,以確保鏈更長。 之後,我在節點1上調用 GET /nodes/resolve ,在節點1上的鏈被共識算法所取代:
ConsensusAlgorithm at Work
去找幾個朋友測試一下你的Blockchain吧。
我希望這能激勵你去創造一些新的東西。 我對加密貨幣感到興奮,因為我相信區塊鏈會迅速改變我們對經濟、政府和記錄保存的看法。
風險警示: 藍狐所有文章都不構成投資推薦,投資有風險,建議對項目進行深入考察,慎重做好自己的投資決策。
相關閱讀
原文作者:Danielvan Flymen
原文地址:hackernoon.com
譯者:由藍狐筆記社群“iGreenMind”翻譯
本文由 @藍狐筆記社群“iGreenMind” 翻譯發佈於人人都是產品經理。 未經許可,禁止轉載。
題圖來自 Pexels,基於 CC0 協議