學習區(qū)塊鏈的最好方法是構(gòu)建一個(上)

0 評論 9078 瀏覽 27 收藏 29 分鐘

深入理解區(qū)塊鏈最好的方式莫過于親手搭建一個,在這個過程中理解它背后的邏輯和原理。

你來這里是因為和我一樣,你對加密貨幣的崛起感到興奮。你想了解區(qū)塊鏈是如何工作的,它們背后的基本技術原理是怎樣的。

但了解區(qū)塊鏈并不容易,至少對我來說不是很容易的。我喜歡邊干邊學。它迫使我在代碼級別上處理問題,這種方法可以讓我堅持學習下去。

記住,區(qū)塊鏈是一個不可變的、有順序的鏈記錄,我們稱之為區(qū)塊。它們可以包含交易、文件或任何你想要的數(shù)據(jù)。但重要的是它們是用哈希鏈接在一起。

這個指南最適合的閱讀對象的要求是什么?至少你輕松地閱讀和編寫一些基本的Python,并了解HTTP請求是如何工作的,因為我們將通過HTTP協(xié)議與我們的 Blockchain 進行交互。

需要什么工具和環(huán)境?確保安裝了Python 3.6+(以及 pip ),還需要安裝Flask和Requests庫:

pip install Flask==0.12.2 requests==2.18.4

你還需要一個HTTP客戶端,比如Postman或cURL??捎玫脑创a請點擊:https://github.com/dvf/blockchain

第一步:構(gòu)建Blockchain

打開你喜歡的文本編輯器或IDE,我比較喜歡使用 PyCharm。然后創(chuàng)建一個名為blockchain.py的新文件。只使用這一個文件,但是如果搞丟了此文件,你可以一直引用源代碼:https://github.com/dvf/blockchain

(1)區(qū)塊鏈藍圖

我們將創(chuàng)建一個區(qū)塊鏈 類,它的構(gòu)造函數(shù)會創(chuàng)建一個初始空列表用于存儲區(qū)塊鏈,另一個用于存儲交易。這是我們創(chuàng)建的區(qū)塊鏈class?的源碼:

1.?????????????class?Blockchain(object):

2.?????????????????def?__init__(self):

3.?????????????????????self.chain?=?[]

4.?????????????????????self.current_transactions?=?[]

5.

6.?????????????????def?new_block(self):

7.?????????????????????#?Creates?a?new?Block?and?adds?it?to?the?chain

8.?????????????????????pass

9.

10.??????????????def?new_transaction(self):

11.???????????????????#?Adds?a?new?transaction?to?the?list?of?transactions

12.??????????????????pass

13.

14.??????????????@staticmethod

15.??????????????def?hash(block):

16.??????????????????#?Hashes?a?Block

17.??????????????????pass

18.

19.??????????????@property

20.??????????????def?last_block(self):

21.??????????????????#?Returns?the?last?Block?in?the?chain

22.??????????????????pass

Blueprint of our Blockchain Class

區(qū)塊鏈 class 負責管理鏈。它將存儲交易,并有一些輔助方法來為鏈添加新的區(qū)塊。讓我們開始充實一些方法。

一個區(qū)塊會是什么樣子?

每個塊都有一個索引、一個時間戳(Unix時間)、一個交易列表、一個證明和前一個塊的哈希值。

區(qū)塊源碼例子:

1.?????????????block?=?{

2.?????????????????‘index’:?1,

3.?????????????????‘timestamp’:?1506057125.900785,

4.?????????????????‘transactions’:?[

5.?????????????????????{

6.?????????????????????????‘sender’:?“8527147fe1f5426f9dd545de4b27ee00”,

7.?????????????????????????‘recipient’:?“a77f5cdfa2934df3954a5c7c7da5df1f”,

8.?????????????????????????‘amount’:?5,

9.?????????????????????}

10.??????????????],

11.???????????????‘proof’:?324984774000,

12.??????????????‘previous_hash’:?“2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824”

13.??????????}

鏈的概念應該很明顯:每個新塊都包含在其內(nèi)部的前一個塊的哈希。這點是至關重要的,因為它使 Blockchain 不可篡改:如果攻擊者破壞了鏈中較早的區(qū)塊,那么隨后所有的塊都將包含不正確的哈希值。

請花一些時間好好去理解它——這是區(qū)塊鏈設計的的核心理念。

(2)在區(qū)塊中添加交易

我們需要一種將交易添加到塊中的方法。new_transaction() 方法可以實現(xiàn)這個功能,而且非常簡單:

1.?????????????class?Blockchain(object):

2.?????????????????…

3.

4.?????????????????def?new_transaction(self,?sender,?recipient,?amount):

5.?????????????????????“””

6.?????????????????????Creates?a?new?transaction?to?go?into?the?next?mined?Block

7.

8.?????????????????????:param?sender:?<str>?Address?of?the?Sender

9.?????????????????????:param?recipient:?<str>?Address?of?the?Recipient

10.??????????????????:param?amount:?<int>?Amount

11.???????????????????:return:?<int>?The?index?of?the?Block?that?will?hold?this?transaction

12.??????????????????“””

13.

14.??????????????????self.current_transactions.append({

15.??????????????????????‘sender’:?sender,

16.??????????????????????‘recipient’:?recipient,

17.??????????????????????‘amount’:?amount,

18.??????????????????})

19.

20.??????????????????return?self.last_block[‘index’]?+?1

在new_transaction()將交易添加到列表之后,它將返回這個交易會被添加到下一個塊的索引。這對稍后提交交易的用戶有用。

(3)創(chuàng)建新區(qū)塊

當 區(qū)塊鏈被實例化時,需要將它與一個沒有前輩的創(chuàng)世區(qū)塊一起連接起來。我們還需要向我們的創(chuàng)世區(qū)塊添加一個“證明”,這是挖礦的結(jié)果。

除了在我們的構(gòu)造函數(shù)中創(chuàng)建創(chuàng)世區(qū)塊之外,我們還將為new_block()、new_transaction()和hash()添加方法:

1.?????????????import?hashlib

2.?????????????import?json

3.?????????????from?time?import?time

4.

5.

6.?????????????class?Blockchain(object):

7.?????????????????def?__init__(self):

8.?????????????????????self.current_transactions?=?[]

9.?????????????????????self.chain?=?[]

10.

11.???????????????????#?Create?the?genesis?block

12.??????????????????self.new_block(previous_hash=1,?proof=100)

13.

14.??????????????def?new_block(self,?proof,?previous_hash=None):

15.??????????????????“””

16.??????????????????Create?a?new?Block?in?the?Blockchain

17.

18.??????????????????:param?proof:?<int>?The?proof?given?by?the?Proof?of?Work?algorithm

19.??????????????????:param?previous_hash:?(Optional)?<str>?Hash?of?previous?Block

20.??????????????????:return:?<dict>?New?Block

21.??????????????????“””

22.

23.??????????????????block?=?{

24.??????????????????????‘index’:?len(self.chain)?+?1,

25.??????????????????????‘timestamp’:?time(),

26.??????????????????????‘transactions’:?self.current_transactions,

27.??????????????????????‘proof’:?proof,

28.??????????????????????‘previous_hash’:?previous_hash?or?self.hash(self.chain[-1]),

29.??????????????????}

30.

31.??????????????????#?Reset?the?current?list?of?transactions

32.??????????????????self.current_transactions?=?[]

33.

34.??????????????????self.chain.append(block)

35.??????????????????return?block

36.

37.??????????????def?new_transaction(self,?sender,?recipient,?amount):

38.??????????????????“””

39.??????????????????Creates?a?new?transaction?to?go?into?the?next?mined?Block

40.

41.??????????????????:param?sender:?<str>?Address?of?the?Sender

42.??????????????????:param?recipient:?<str>?Address?of?the?Recipient

43.??????????????????:param?amount:?<int>?Amount

44.??????????????????:return:?<int>?The?index?of?the?Block?that?will?hold?this?transaction

45.??????????????????“””

46.??????????????????self.current_transactions.append({

47.??????????????????????‘sender’:?sender,

48.??????????????????????‘recipient’:?recipient,

49.??????????????????????‘amount’:?amount,

50.??????????????????})

51.

52.??????????????????return?self.last_block[‘index’]?+?1

53.

54.??????????????@property

55.??????????????def?last_block(self):

56.??????????????????return?self.chain[-1]

57.

58.??????????????@staticmethod

59.??????????????def?hash(block):

60.??????????????????“””

61.??????????????????Creates?a?SHA-256?hash?of?a?Block

62.

63.??????????????????:param?block:?<dict>?Block

64.??????????????????:return:?<str>

65.??????????????????“””

66.

67.??????????????????#?We?must?make?sure?that?the?Dictionary?is?Ordered,?or?we’ll?have?inconsistent?hashes

68.??????????????????block_string?=?json.dumps(block,?sort_keys=True).encode()

69.??????????????????return?hashlib.sha256(block_string).hexdigest()

70.

至此,我們幾乎完成了 Blockchain 的代碼化表現(xiàn)。但新的區(qū)塊是如何被創(chuàng)建、挖掘的?

(4)理解PoW工作量證明

工作量證明,也就是新的區(qū)塊如何在 Blockchain 上被創(chuàng)建或挖掘出來。它的目標是發(fā)現(xiàn)一個解決問題的數(shù)字,這個數(shù)字一定很難找到,但卻很容易被驗證——在網(wǎng)絡上的任何人都可以通過計算來驗證,這是工作證明PoW背后的核心思想。

我們來看一個非常簡單的例子:我們想找到這樣一個數(shù)值,將整數(shù)x與另一個數(shù)值y的乘積進行hash運算,使得運算的結(jié)果是一串字符串的結(jié)尾必須是數(shù)字0 。用數(shù)學表達式表示出來就是:

hash(x * y) = ac23dc…0

我們假定x = 5。在Python中實現(xiàn),代碼如下:

1.?????????????from?hashlib?import?sha256

2.?????????????x?=?5

3.?????????????y?=?0??#?We?don’t?know?what?y?should?be?yet…

4.?????????????while?sha256(f'{x*y}’.encode()).hexdigest()[-1]?!=?“0”:

5.?????????????????y?+=?1

6.?????????????print(f’The?solution?is?y?=?{y}’)

這里的解是y = 21。因為,生成的hash值是以0結(jié)尾的:

1.?hash(5?*?21)?=?1253e9373e…5e3600155e860

在比特幣中,工作量證明被稱為Hashcash 。它和上面舉出的簡單例子基本沒有太大區(qū)別。這是為了創(chuàng)建一個新的區(qū)塊,礦工們競相解決問題的算法。一般來說,難度取決于字符串中搜索的字符數(shù)。

礦工會因為在一個交易中找到了那個難題的解,而獲得系統(tǒng)給出的激勵:該網(wǎng)絡的一定量的數(shù)字貨幣。該網(wǎng)絡能夠很容易地驗證他們的解是否正確。

(5)實現(xiàn)基本的工作量證明

為區(qū)塊鏈實現(xiàn)一個類似的算法,規(guī)則與上面類似:找到一個數(shù)字p,當與上一個區(qū)塊的解進行哈希運算時,產(chǎn)生一個前4位都是0的哈希值。

為了調(diào)整算法的難度,我們可以修改前幾位零的個數(shù)。但4個0就足夠了。你將發(fā)現(xiàn),添加一個前導零就會對找到解所需的時間造成很大的不同。

1.?????????????import?hashlib

2.?????????????import?json

3.

4.?????????????from?time?import?time

5.?????????????from?uuid?import?uuid4

6.

7.

8.?????????????class?Blockchain(object):

9.?????????????????…

10.

11.???????????????def?proof_of_work(self,?last_proof):

12.??????????????????“””

13.??????????????????Simple?Proof?of?Work?Algorithm:

14.???????????????????–?Find?a?number?p’?such?that?hash(pp’)?contains?leading?4?zeroes,?where?p?is?the?previous?p’

15.???????????????????–?p?is?the?previous?proof,?and?p’?is?the?new?proof

16.

17.??????????????????:param?last_proof:?<int>

18.??????????????????:return:?<int>

19.??????????????????“””

20.

21.??????????????????proof?=?0

22.??????????????????while?self.valid_proof(last_proof,?proof)?is?False:

23.??????????????????????proof?+=?1

24.

25.??????????????????return?proof

26.

27.??????????????@staticmethod

28.??????????????def?valid_proof(last_proof,?proof):

29.??????????????????“””

30.??????????????????Validates?the?Proof:?Does?hash(last_proof,?proof)?contain?4?leading?zeroes?

31.

32.??????????????????:param?last_proof:?<int>?Previous?Proof

33.??????????????????:param?proof:?<int>?Current?Proof

34.??????????????????:return:?<bool>?True?if?correct,?False?if?not.

35.??????????????????“””

36.

37.??????????????????guess?=?f'{last_proof}{proof}’.encode()

38.??????????????????guess_hash?=?hashlib.sha256(guess).hexdigest()

39.??????????????????return?guess_hash[:4]?==?“0000”

我們的類接近完成,我們已經(jīng)準備好使用HTTP請求開始與它交互。

第二步:將區(qū)塊鏈作為API使用起來

使用Python的Flask框架。它是一個微型框架,它可以很容易地將端點映射到Python函數(shù)。這讓我們使用HTTP請求在web上與 Blockchain 進行交互。

我們將創(chuàng)建三個方法:

  1. /transactions/new?? 創(chuàng)建一個新的交易到一個區(qū)塊。
  2. /mine?? 告訴我們的服務器去挖掘一個新的區(qū)塊。
  3. /chain?返回完整的 Blockchain 。

設置Flask

我們的“服務器”將在 Blockchain 網(wǎng)絡中形成單獨節(jié)點,創(chuàng)建一些樣板代碼如下所示:

1.?????????????import?hashlib

2.?????????????import?json

3.?????????????from?textwrap?import?dedent

4.?????????????from?time?import?time

5.?????????????from?uuid?import?uuid4

6.

7.?????????????from?flask?import?Flask

8.

9.

10.??????????class?Blockchain(object):

11.???????????????…

12.

13.

14.??????????#?Instantiate?our?Node

15.??????????app?=?Flask(__name__)

16.

17.??????????#?Generate?a?globally?unique?address?for?this?node

18.??????????node_identifier?=?str(uuid4()).replace(‘-‘,?”)

19.

20.??????????#?Instantiate?the?Blockchain

21.??????????blockchain?=?Blockchain()

22.

23.

24.??????????@app.route(‘/mine’,?methods=[‘GET’])

25.??????????def?mine():

26.??????????????return?“We’ll?mine?a?new?Block”

27.

28.??????????@app.route(‘/transactions/new’,?methods=[‘POST’])

29.??????????def?new_transaction():

30.??????????????return?“We’ll?add?a?new?transaction”

31.

32.??????????@app.route(‘/chain’,?methods=[‘GET’])

33.??????????def?full_chain():

34.??????????????response?=?{

35.??????????????????‘chain’:?blockchain.chain,

36.??????????????????‘length’:?len(blockchain.chain),

37.??????????????}

38.??????????????return?jsonify(response),?200

39.

40.??????????if?__name__?==?‘__main__’:

41.??????????????app.run(host=’0.0.0.0′,?port=5000)

關于在上面代碼中添加的內(nèi)容的簡要說明如下:

  • Line 15:?實例化節(jié)點。
  • Line 18:?為我們的節(jié)點創(chuàng)建一個隨機名稱。
  • Line 21:?實例化我們的Blockchain類。
  • Line 24–26:?創(chuàng)建/mine 端點,這是一個GET請求。
  • Line 28–30:?創(chuàng)建 /transactions/new?端點,這是一個POST 請求,因為我們將向它發(fā)送數(shù)據(jù)。
  • Line 32–38:?創(chuàng)建/chain端點,它返回完整的 Blockchain 。
  • Line 40–41:?在端口5000上運行服務器。

交易端點

這就是交易請求的樣子。這是用戶發(fā)送給服務器的內(nèi)容:

1.?????????????{

2.??????????????“sender”:?“my?address”,

3.??????????????“recipient”:?“someone?else’s?address”,

4.??????????????“amount”:?5

5.?????????????}

由于已經(jīng)有了將交易添加到區(qū)塊的類的方法,其余的都很簡單。讓我們編寫添加交易的函數(shù):

1.?????????????import?hashlib

2.?????????????import?json

3.?????????????from?textwrap?import?dedent

4.?????????????from?time?import?time

5.?????????????from?uuid?import?uuid4

6.

7.?????????????from?flask?import?Flask,?jsonify,?request

8.

9.?????????????…

10.

11.???????????@app.route(‘/transactions/new’,?methods=[‘POST’])

12.??????????def?new_transaction():

13.??????????????values?=?request.get_json()

14.

15.??????????????#?Check?that?the?required?fields?are?in?the?POST’ed?data

16.??????????????required?=?[‘sender’,?‘recipient’,?‘amount’]

17.??????????????if?not?all(k?in?values?for?k?in?required):

18.??????????????????return?‘Missing?values’,?400

19.

20.??????????????#?Create?a?new?Transaction

21.??????????????index?=?blockchain.new_transaction(values[‘sender’],?values[‘recipient’],?values[‘amount’])

22.

23.??????????????response?=?{‘message’:?f’Transaction?will?be?added?to?Block?{index}’}

24.??????????????return?jsonify(response),?201

Amethod for creating Transactions

挖礦端點

挖礦端點必須做三件事:

(1)計算工作量證明。

(2)通過增加一筆交易,獎賞給礦工(也就是我們自己)一定量的數(shù)字貨幣。

(3)通過將新區(qū)塊添加到鏈中來鍛造區(qū)塊。

1.?????????????import?hashlib

2.?????????????import?json

3.

4.?????????????from?time?import?time

5.?????????????from?uuid?import?uuid4

6.

7.?????????????from?flask?import?Flask,?jsonify,?request

8.

9.?????????????…

10.

11.???????????@app.route(‘/mine’,?methods=[‘GET’])

12.??????????def?mine():

13.??????????????#?We?run?the?proof?of?work?algorithm?to?get?the?next?proof…

14.??????????????last_block?=?blockchain.last_block

15.??????????????last_proof?=?last_block[‘proof’]

16.??????????????proof?=?blockchain.proof_of_work(last_proof)

17.

18.??????????????#?We?must?receive?a?reward?for?finding?the?proof.

19.??????????????#?The?sender?is?“0”?to?signify?that?this?node?has?mined?a?new?coin.

20.??????????????blockchain.new_transaction(

21.??????????????????sender=”0″,

22.??????????????????recipient=node_identifier,

23.??????????????????amount=1,

24.??????????????)

25.

26.??????????????#?Forge?the?new?Block?by?adding?it?to?the?chain

27.??????????????previous_hash?=?blockchain.hash(last_block)

28.??????????????block?=?blockchain.new_block(proof,?previous_hash)

29.

30.??????????????response?=?{

31.??????????????????‘message’:?“New?Block?Forged”,

32.??????????????????‘index’:?block[‘index’],

33.??????????????????‘transactions’:?block[‘transactions’],

34.??????????????????‘proof’:?block[‘proof’],

35.??????????????????‘previous_hash’:?block[‘previous_hash’],

36.??????????????}

37.??????????????return?jsonify(response),?200

被挖掘出來的區(qū)塊的接收者是我們節(jié)點的地址。在這里所做的大部分工作只是與Blockchain class中的方法進行交互。在這一點上,我們已經(jīng)完成了,并且可以開始與我們的 Blockchain 進行交互了。

——未完待續(xù)——

風險警示:藍狐所有文章都不構(gòu)成投資推薦,投資有風險,建議對項目進行深入考察,慎重做好自己的投資決策。

 

原文作者:Danielvan Flymen

原文地址:hackernoon.com

譯者:由藍狐筆記社群“iGreenMind”翻譯

本文由 @藍狐筆記社群“iGreenMind” 翻譯發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。

題圖來自 Pexels,基于 CC0 協(xié)議

更多精彩內(nèi)容,請關注人人都是產(chǎn)品經(jīng)理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發(fā)揮!