学习区块链的最好方法是构建一个(上)


原创 DanielvanFlymen

前言:深入理解区块链最好的方式莫过于亲手搭建一个,在这个过程中理解它背后的逻辑和原理。本文作者是Danielvan
Flymen ,文章来源于hackernoon.com,由蓝狐笔记社群“iGreenMind”翻译。

 

你来这里是因为和我一样,你对加密货币的崛起感到兴奋。你想了解区块链是如何工作的,它们背后的基本技术原理是怎样的。

 

但了解区块链并不容易,至少对我来说不是很容易的。我喜欢边干边学。它迫使我在代码级别上处理问题,这种方法可以让我坚持学习下去。

 

记住,区块链是一个不可变的、有顺序的链记录,我们称之为区块。它们可以包含交易、文件或任何你想要的数据。但重要的是它们是用哈希链接在一起。

 

这个指南最适合的阅读对象的要求是什么?至少你轻松地阅读和编写一些基本的Python,并了解HTTP请求是如何工作的,因为我们将通过HTTP协议与我们的
Blockchain 进行交互。

 

需要什么工具和环境?确保安装了Python 3.6+(以及 pip
),还需要安装Flask和Requests库:

\

pip install Flask==0.12.2 requests==2.18.4

 

你还需要一个HTTP客户端,比如Postman或cURL。可用的源代码请点击:https://github.com/dvf/blockchain

  {style=”margin-bottom: 0.1px;white-space: normal;background: white;text-align: justify;”}

第一步:构建**Blockchain** {style=”margin-bottom: 0.1px;white-space: normal;background: white;text-align: justify;”}

\

打开你喜欢的文本编辑器或IDE,我比较喜欢使用
PyCharm。然后创建一个名为blockchain.py的新文件。只使用这一个文件,但是如果搞丢了此文件,你可以一直引用源代码:https://github.com/dvf/blockchain

 

 区块链蓝图

 

我们将创建一个区块链
类,它的构造函数会创建一个初始空列表用于存储区块链,另一个用于存储交易。这是我们创建的区块链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

\

区块链 class
负责管理链。它将存储交易,并有一些辅助方法来为链添加新的区块。让我们开始充实一些方法。

 

一个区块会是什么样子?

 

每个块都有一个索引、一个时间戳(Unix时间)、一个交易列表、一个证明和前一个块的哈希值。

\

区块源码例子:

\

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.          }  

\

链的概念应该很明显:每个新块都包含在其内部的前一个块的哈希。这点是至关重要的,因为它使
Blockchain
不可篡改:如果攻击者破坏了链中较早的区块,那么随后所有的块都将包含不正确的哈希值。

 

请花一些时间好好去理解它——这是区块链设计的的核心理念。

 

在区块中添加交易

\

我们需要一种将交易添加到块中的方法。new_transaction()
方法可以实现这个功能,而且非常简单:

\

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()将交易添加到列表之后,它将返回这个交易会被添加到下一个块的索引。这对稍后提交交易的用户有用。

 

创建新区块

**
**


区块链被实例化时,需要将它与一个没有前辈的创世区块一起连接起来。我们还需要向我们的创世区块添加一个“证明”,这是挖矿的结果。

 

除了在我们的构造函数中创建创世区块之外,我们还将为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
的代码化表现。但新的区块是如何被创建、挖掘的?

 

理解PoW工作量证明

 

工作量证明,也就是新的区块如何在 Blockchain
上被创建或挖掘出来。它的目标是发现一个解决问题的数字,这个数字一定很难找到,但却很容易被验证——在网络上的任何人都可以通过计算来验证,这是工作证明PoW背后的核心思想。

 

我们来看一个非常简单的例子:我们想找到这样一个数值,将整数x与另一个数值y的乘积进行hash运算,使得运算的结果是一串字符串的结尾必须是数字0
。用数学表达式表示出来就是:

\

hash(x * y) = ac23dc…0

\

我们假定x = 5。在Python中实现,代码如下:

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结尾的:

\

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

\

在比特币中,工作量证明被称为Hashcash
。它和上面举出的简单例子基本没有太大区别。这是为了创建一个新的区块,矿工们竞相解决问题的算法。一般来说,难度取决于字符串中搜索的字符数。

\

矿工会因为在一个交易中找到了那个难题的解,而获得系统给出的激励:该网络的一定量的数字货币。该网络能够很容易地验证他们的解是否正确。

 

实现基本的工作量证明

 

为区块链实现一个类似的算法,规则与上面类似:找到一个数字p,当与上一个区块的解进行哈希运算时,产生一个前4位都是0的哈希值。

\

为了调整算法的难度,我们可以修改前几位零的个数。但4个0就足够了。你将发现,添加一个前导零就会对找到解所需的时间造成很大的不同。

\

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”  

\

我们的类接近完成,我们已经准备好使用HTTP请求开始与它交互。

  {style=”margin-bottom: 0.1px;white-space: normal;background: white;text-align: justify;”}

第二步:将区块链作为API使用起来 {style=”margin-bottom: 0.1px;white-space: normal;background: white;text-align: justify;”}

\

使用Python的Flask框架。它是一个微型框架,它可以很容易地将端点映射到Python函数。这让我们使用HTTP请求在web上与
Blockchain 进行交互。

\

我们将创建三个方法:

/transactions/new   创建一个新的交易到一个区块。

/mine   告诉我们的服务器去挖掘一个新的区块。

/chain 返回完整的 Blockchain 。

\

设置Flask {style=”margin-bottom: 0.1px;font-size: medium;white-space: normal;line-height: normal;background: white;text-align: justify;”}

**
**

我们的“服务器”将在 Blockchain
网络中形成单独节点,创建一些样板代码如下所示:

\

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)  

\

关于在上面代码中添加的内容的简要说明如下:

\

Line 15: 实例化节点。

Line 18: 为我们的节点创建一个随机名称。

Line 21: 实例化我们的Blockchain类。

Line 24–26: 创建/mine 端点,这是一个GET请求。

Line 28–30: 创建 /transactions/new 端点,这是一个POST
请求,因为我们将向它发送数据。

Line 32–38: 创建/chain端点,它返回完整的 Blockchain 。

Line 40–41: 在端口5000上运行服务器。

\

交易端点 {style=”margin-bottom: 0.1px;font-size: medium;white-space: normal;line-height: normal;background: white;text-align: justify;”}

**
**

这就是交易请求的样子。这是用户发送给服务器的内容:

 

1.             {  

2.              “sender”: “my address”,  

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

4.              “amount”: 5  

5.             }  

 

由于已经有了将交易添加到区块的类的方法,其余的都很简单。让我们编写添加交易的函数:

 

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. 通过增加一笔交易,奖赏给矿工(也就是我们自己)一定量的数字货币。

3. 通过将新区块添加到链中来锻造区块。

 

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  

 

被挖掘出来的区块的接收者是我们节点的地址。在这里所做的大部分工作只是与Blockchain
class中的方法进行交互。在这一点上,我们已经完成了,并且可以开始与我们的
Blockchain 进行交互了。

\

——未完待续——

\

风险警示:蓝狐所有文章都不构成投资推荐,投资有风险,建议对项目进行深入考察,慎重做好自己的投资决策。

\

想要深入了解区块链,长按下面二维码关注“蓝狐笔记”区块链公众号:lanhubiji
或加入知识星球:https://t.zsxq.com/iaQNnIq(6月28日到期,建议6月28号后再加入)

\

#

学习区块链的最好方法是构建一个(上)


欢迎加入蓝狐笔记群微信:donnell008

×

喜欢就点赞,疼爱就打赏