學(xué)習(xí)區(qū)塊鏈的最好方法是構(gòu)建一個(gè)(下)
深入理解區(qū)塊鏈最好的方式莫過于親手搭建一個(gè),在這個(gè)過程中理解它背后的邏輯和原理。
接上一篇《學(xué)習(xí)區(qū)塊鏈的最好方法是構(gòu)建一個(gè)(上)》
第三步:與我們的區(qū)塊鏈交互
你可以使用普通的cURL或Postman工具,通過網(wǎng)絡(luò)與我們的API進(jìn)行交互。
啟動(dòng)服務(wù)器:
1.? ??$?python?blockchain.py
2.? ? ?*?Running?on?http://127.0.0.1:5000/?(Press?CTRL+C?to?quit)
讓我們嘗試通過向http://localhost:5000/mine發(fā)出GET請求來挖掘一個(gè)區(qū)塊:
UsingPostman to make a GET?request
讓我們通過向http://localhost:5000/transactions/new? 發(fā)出一個(gè)POST請求來創(chuàng)建一個(gè)新的交易,這個(gè)交易包含了交易結(jié)構(gòu)的主體:
UsingPostman to make a POST?request
如果你不使用 Postman 工具,同樣可以使用cURL這個(gè)工具來實(shí)現(xiàn)同樣的目的:
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”
重啟了我的服務(wù)器,并挖掘了兩個(gè)區(qū)塊,總共給出了3個(gè)區(qū)塊。讓我們通過請求http://localhost:5000/chain檢查整個(gè)鏈:
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.??????????}
第四步:共識(shí)
這非???。我們有一個(gè)基本的 Blockchain 接受交易,它允許我們挖掘新的區(qū)塊。但 Blockchain 的關(guān)鍵在于,它們應(yīng)該是分布式的。如果它們是分布式的,我們?nèi)绾未_保它們都在一條鏈?這被稱為共識(shí)的問題,如果我們想要在我們的網(wǎng)絡(luò)中有多個(gè)節(jié)點(diǎn),我們就必須實(shí)現(xiàn)一個(gè)共識(shí)的算法。
注冊新節(jié)點(diǎn)
在實(shí)現(xiàn)共識(shí)算法之前,我們需要一種方法讓節(jié)點(diǎn)知道網(wǎng)絡(luò)上的相鄰節(jié)點(diǎn)。我們網(wǎng)絡(luò)上的每個(gè)節(jié)點(diǎn)都應(yīng)該保留網(wǎng)絡(luò)上其他節(jié)點(diǎn)的注冊表。因此,我們需要更多的端點(diǎn):
1.?/nodes/register?以url的形式接受新的節(jié)點(diǎn)列表。
2.??/nodes/resolve?? 來實(shí)現(xiàn)我們的共識(shí)算法,它可以解決任何沖突——以確保一個(gè)節(jié)點(diǎn)擁有正確的鏈。
我們需要修改 Blockchain 的構(gòu)造函數(shù),并提供注冊節(jié)點(diǎn)的方法:
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:?<str>?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()來保存節(jié)點(diǎn)列表。這是確保新節(jié)點(diǎn)的添加具有冪等性的廉價(jià)方式,這意味著無論我們添加多少次特定節(jié)點(diǎn),它都只會(huì)出現(xiàn)一次。
實(shí)現(xiàn)算法的共識(shí)
如前所述,當(dāng)一個(gè)節(jié)點(diǎn)與另一個(gè)節(jié)點(diǎn)具有不同鏈時(shí)就有了沖突。為了解決這個(gè)問題,我們制定一條規(guī)則:最長的并且有效的鏈才是權(quán)威的。換句話說,網(wǎng)絡(luò)上最長的鏈?zhǔn)鞘聦?shí)上的鏈。利用該算法,我們在網(wǎng)絡(luò)節(jié)點(diǎn)之間達(dá)成了一致。
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:?<list>?A?blockchain
13.??????????????????:return:?<bool>?True?if?valid,?False?if?not
14.??????????????????“””
15.
16.??????????????????last_block?=?chain[0]
17.??????????????????current_index?=?1
18.
19.??????????????????while?current_index?<?len(chain):
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:?<bool>?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
第一個(gè)方法valid_chain() 負(fù)責(zé)檢查鏈?zhǔn)欠裼行?,通過循環(huán)遍歷每個(gè)區(qū)塊并驗(yàn)證哈希和證明。
resolve_conflicts() 是這么一個(gè)方法:它遍歷我們所有的鄰近節(jié)點(diǎn),下載它們的鏈并使用上面的方法驗(yàn)證它們。如果一個(gè)有效的鏈被發(fā)現(xiàn),它的長度大于我們的,我們就替換掉我們當(dāng)前所使用的鏈。
讓我們將兩個(gè)端點(diǎn)注冊到API中,一個(gè)用于添加相鄰節(jié)點(diǎn),另一個(gè)用于解決沖突:
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
此時(shí),你可以使用不同的機(jī)器,并在網(wǎng)絡(luò)上創(chuàng)建不同的節(jié)點(diǎn)?;蛘咴谕慌_(tái)機(jī)器上使用不同的端口來啟動(dòng)進(jìn)程。我在我的機(jī)器上的另一個(gè)端口上啟動(dòng)了另一個(gè)節(jié)點(diǎn),并將它注冊到我當(dāng)前的節(jié)點(diǎn)上。因此,我有兩個(gè)節(jié)點(diǎn):? http://localhost:5000? 和 http://localhost:5001? 。
Registeringa new?Node
然后我在節(jié)點(diǎn)2上挖掘了一些新的區(qū)塊,以確保鏈更長。之后,我在節(jié)點(diǎn)1上調(diào)用 GET /nodes/resolve? ,在節(jié)點(diǎn)1上的鏈被共識(shí)算法所取代:
ConsensusAlgorithm at?Work
去找?guī)讉€(gè)朋友測試一下你的Blockchain吧。
我希望這能激勵(lì)你去創(chuàng)造一些新的東西。我對加密貨幣感到興奮,因?yàn)槲蚁嘈艆^(qū)塊鏈會(huì)迅速改變我們對經(jīng)濟(jì)、政府和記錄保存的看法。
風(fēng)險(xiǎn)警示:藍(lán)狐所有文章都不構(gòu)成投資推薦,投資有風(fēng)險(xiǎn),建議對項(xiàng)目進(jìn)行深入考察,慎重做好自己的投資決策。
相關(guān)閱讀
學(xué)習(xí)區(qū)塊鏈的最好方法是構(gòu)建一個(gè)(上)
原文作者:Danielvan Flymen
原文地址:hackernoon.com
譯者:由藍(lán)狐筆記社群“iGreenMind”翻譯
本文由 @藍(lán)狐筆記社群“iGreenMind” 翻譯發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來自 Pexels,基于 CC0 協(xié)議
很不錯(cuò),我一個(gè)開發(fā)的看了都覺得蠻清楚的