手把手:用Python实现一个基于RSA算法的区块链客户端

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

区块链作为比特币和其他加密货币的核心技术,在最近几年引起了全世界的注意,但是各国这一颠覆性的技术态度不一,因为其去中心化的分布式结构,可以使用户之间直接进行交流,无需中心节点参与的这种技术模式对银行、证券等机构带来了极大影响。

区块链的技术模式和各国对区块链的态度:

而在本篇文章,抛开介绍区块链的技术特点和应用场景,文摘菌手把手的教大家如何用python实现一个基础的区块链,和一个区块链的客户端。

我们实现的区块链有如下几个特性:

  • 可以向区块链中添加多个节点。

  • 工作量证明(PoW)。

  • 简单的节点间冲突解决机制。

  • 使用RSA 加密进行交易。

我们的区块链客户端有如下几个功能:

  • 使用公钥/私钥加密技术生成钱包。(基于RSA算法)。

  • 使用RSA 加密算法生成交易。

我们还实现了2个展示界面:

  • 挖矿者使用的“区块链前端”

  • 用户生成钱包和发币的“区块链客户端”

我在原始代码的基础上进行了一些改动,向交易中加入了RSA加密,并实现了钱包生成和交易加密,两个界面使用HTML/CSS/JS 实现。

完整的项目代码:

https://github.com/adilmoujahid/blockchain-python-tutorial

请注意,这个实现是用于教学目的,所以它不适用于生产环境。因为它保密性不够,且缺乏一些重要的特性。

区块链客户端实现

你可以从终端启动区块链客户端。进入blockchain_client文件夹,并输入命令:python blockchain_client.py。

在浏览器中打开http://localhost:8080,接下来你会看到如下展示界面。

0eb50913043dd92a0f73e9ee57f5ca932e80571f

展示界面导航栏有3个标签:

  • 钱包生成器:使用RSA加密算法生成钱包(公钥/私钥对)。

  • 生成交易:生成交易并将其发送到区块链节点。

  • 查看交易:查看区块链上的交易。

要想生成交易或查看交易,至少需要一个区块链节点在运行(将在下一节中介绍)。

blockchain_client.py文件代码中一些重要部分的说明:我们定义了一个Python类,我们命名了4个属性字段:sender_address,sender_private_key,recipient_address,value。

这是发送方创建交易所需的4个信息。

to_dict()方法返回一个Python字典格式交易信息(没有发件人的私钥)。

sign_transaction()方法接收交易信息(没有发件人的私钥),然后使用发送者的私钥进行签名。

 
class Transaction:

   def __init__(self, sender_address, sender_private_key, recipient_address, value):

       self.sender_address = sender_address

       self.sender_private_key = sender_private_key

       self.recipient_address = recipient_address

       self.value = value



   def __getattr__(self, attr):

       return self.data[attr]



   def to_dict(self):

       return OrderedDict({'sender_address': self.sender_address,

                           'recipient_address': self.recipient_address,

                           'value': self.value})



   def sign_transaction(self):

       """

       Sign transaction with private key

       """

       private_key = RSA.importKey(binascii.unhexlify(self.sender_private_key))

       signer = PKCS1_v1_5.new(private_key)

       h = SHA.new(str(self.to_dict()).encode('utf8'))

       return binascii.hexlify(signer.sign(h)).decode('ascii')

下面是初始化一个Python Flask应用的代码行, 我们将用它来创建不同的API来与区块链及其客户进行交互。

 
app = Flask(__name__)

下面我们定义了3个返回HTML页面的Flask路径,其中每个标签都有一个html页面。

@app.route('/')

def index():

 return render_template('./index.html')



@app.route('/make/transaction')

def make_transaction():

   return render_template('./make_transaction.html')



@app.route('/view/transactions')

def view_transaction():

return render_template('./view_transactions.html')

下面我们定义一个生成钱包(私有/公钥对)的API。

@app.route('/wallet/new', methods=['GET'])

def new_wallet():

 random_gen = Crypto.Random.new().read

 private_key = RSA.generate(1024, random_gen)

 public_key = private_key.publickey()

 response = {

   'private_key': binascii.hexlify(private_key.exportKey(format='DER')).decode('ascii'),

   'public_key': binascii.hexlify(public_key.exportKey(format='DER')).decode('ascii')

 }

 return jsonify(response), 200

5c30e86b49a7bf9ff9845e9e989524661dac8873

下面我们定义一个API,将sender_address, sender_private_key, recipient_address, value字段作为输入,并返回交易(没有私钥)和签名。

@app.route('/generate/transaction', methods=['POST'])

def generate_transaction():

 sender_address = request.form['sender_address']

 sender_private_key = request.form['sender_private_key']

 recipient_address = request.form['recipient_address']

 value = request.form['amount']

 transaction = Transaction(sender_address, sender_private_key, recipient_address, value)

 response = {'transaction': transaction.to_dict(), 'signature': transaction.sign_transaction()}

 return jsonify(response), 200
0723f7646a0bf3f4ea8c16f5473e32ecebd1329b

区块链的实现

你可以从终端启动区块链节点,通过进入blockchain文件夹,并输入命令:python blockchain_client.py或python blockchain_client.py -p <PORT NUMBER> 。如果你未指定端口号,则会默认端口号为5000。在浏览器中打开http://localhost:<PORT NUMBER>可以看到区块链前端展示界面。

4a9cb78b36637ffbf7b11fe51cacfd6eb65d14e4

展示界面导航栏有两个标签:

  • 挖掘:用于查看交易和区块链数据,以及挖掘新的交易区块。

  • 配置:用于配置不同区块链节点之间的连接。

下面是blockchain.py文件代码中一些重要部分的说明。

我们首先定义一个具有以下属性的Blockchain类:

  • transactions:将被添加到下一区块的交易列表。

  • chain::实际的区块链,也就是一个区块数组。

  • nodes:一个包含节点URL的集合。区块链使用这些节点从其他节点中检索区块链数据并且在检查到它们没有同步时更新其区块链。

  • node_id:一个标识blockchain节点的随机字符串。

这个Blockchain类还实现了以下方法:

  • register_node(node_url): 将新的区块链节点添加到节点列表中。

  • verify_transaction_signature(sender_address, signature, transaction): 检查提供的签名是否与通过公钥(sender_address)签署的交易相符。

  • submit_transaction(sender_address, recipient_address, value, signature): 如果签名通过验证,则将交易添加到交易列表中。

  • create_block(nonce, previous_hash):向区块链添加一个交易块。

  • hash(block): 创建一个区块的SHA-256散列。

  • proof_of_work():工作算法的证明。寻找满足挖掘条件的随机数。

  • valid_proof(transactions, last_hash, nonce, difficulty=MINING_DIFFICULTY):检查散列值是否满足挖掘条件。该函数在proof_of_work函数中使用。

  • valid_chain(chain): 检查区块链是否有效。

  • resolve_conflicts():通过用网络中最长链代替链的方法解决区块链节点之间的冲突。

 
class Blockchain:

   def __init__(self):

       self.transactions = []

       self.chain = []

       self.nodes = set()

       #Generate random number to be used as node_id

       self.node_id = str(uuid4()).replace('-', '')

       #Create genesis block

       self.create_block(0, '00')



   def register_node(self, node_url):

       """

       Add a new node to the list of nodes

       """

       ...

       

   def verify_transaction_signature(self, sender_address, signature, transaction):

       """

       Check that the provided signature corresponds to transaction



       signed by the public key (sender_address)

       """

       ...



   def submit_transaction(self, sender_address, recipient_address, value, signature):

       """

       Add a transaction to transactions array if the signature verified

       """

       ...



   def create_block(self, nonce, previous_hash):

       """

       Add a block of transactions to the blockchain

       """

        ...



   def hash(self, block):

       """

       Create a SHA-256 hash of a block

       """

       ...



   def proof_of_work(self):

       """

       Proof of work algorithm

       """

       ...



   def valid_proof(self, transactions, last_hash, nonce, difficulty=MINING_DIFFICULTY):

       """

       Check if a hash value satisfies the mining conditions. This function is used within the proof_of_work function.

       """

       ...



   def valid_chain(self, chain):

       """

       check if a bockchain is valid

       """

       ...



   def resolve_conflicts(self):

       """

       Resolve conflicts between blockchain's nodes

       by replacing our chain with the longest one in the network.

       """

       ...

下面这一行,我们初始化了一个Python Flask 应用,用于创建和区块链交互的API。

app = Flask(__name__)

CORS(app)

下面,我们初始化一个区块链对象。

blockchain = Blockchain()

下面我们定义了2种返回我们区块链前端展示界面html页面的Flask路线。

@app.route('/')

def index():

   return render_template('./index.html')



@app.route('/configure')

def configure():

return render_template('./configure.html')

下面我们定义了Flask API来管理交易和挖掘区块链。

此API将'sender_address', 'recipient_address', 'amount' 和 'signature' 作为输入,并且如果签名有效,则将交易添加到将添加到下一个块的交易列表中。

  • '/transactions/get':此API返回所有将会添加到下一个块的交易。

  • '/chain':此API返回所有区块链数据。

  • '/mine': 此API运行工作算法的证明,同时添加新的交易块到区块链。

 

@app.route('/transactions/new', methods=['POST'])

def new_transaction():

   values = request.form

   # Check that the required fields are in the POST'ed data

   required = ['sender_address', 'recipient_address', 'amount', 'signature']

   if not all(k in values for k in required):

       return 'Missing values', 400

   # Create a new Transaction

   transaction_result = blockchain.submit_transaction(values['sender_address'], values['recipient_address'], values['amount'], values['signature'])

   if transaction_result == False:

       response = {'message': 'Invalid Transaction!'}

       return jsonify(response), 406

   else:

       response = {'message': 'Transaction will be added to Block '+ str(transaction_result)}

       return jsonify(response), 201



@app.route('/transactions/get', methods=['GET'])

def get_transactions():

   #Get transactions from transactions pool

   transactions = blockchain.transactions

   response = {'transactions': transactions}

   return jsonify(response), 200



@app.route('/chain', methods=['GET'])

def full_chain():

   response = {

       'chain': blockchain.chain,

       'length': len(blockchain.chain),

   }

   return jsonify(response), 200

@app.route('/mine', methods=['GET'])

def mine():

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

   last_block = blockchain.chain[-1]

   nonce = blockchain.proof_of_work()

   # We must receive a reward for finding the proof.

   blockchain.submit_transaction(sender_address=MINING_SENDER, recipient_address=blockchain.node_id, value=MINING_REWARD, signature="")

   # Forge the new Block by adding it to the chain

   previous_hash = blockchain.hash(last_block)

   block = blockchain.create_block(nonce, previous_hash)

   response = {

       'message': "New Block Forged",

       'block_number': block['block_number'],

       'transactions': block['transactions'],

       'nonce': block['nonce'],

       'previous_hash': block['previous_hash'],

   }

return jsonify(response), 200

629746aa24ba3c4a2ca83f743b41aa58ef4ca097

下面我们定义Flask API来管理区块链节点。

  • '/nodes/register':此API将节点URL列表作为输入,同时添加URL到节点列表。

  • '/nodes/resolve':此API通过使用网络中最长的可用链替代本地链的方式解决区块链节点间的冲突。

  • '/nodes/get':此API返回节点列表。

 

@app.route('/nodes/register', methods=['POST'])

def register_nodes():

   values = request.form

   nodes = values.get('nodes').replace(" ", "").split(',')

   if nodes is None:

       return "Error: Please supply a valid list of nodes", 400

   for node in nodes:

       blockchain.register_node(node)

   response = {

       'message': 'New nodes have been added',

       'total_nodes': [node for node in blockchain.nodes],

   }

   return jsonify(response), 201



@app.route('/nodes/resolve', methods=['GET'])

def consensus():

   replaced = blockchain.resolve_conflicts()

   if replaced:

       response = {

           'message': 'Our chain was replaced',

           'new_chain': blockchain.chain

       }

   else:

       response = {

           'message': 'Our chain is authoritative',

           'chain': blockchain.chain

       }

   return jsonify(response), 200

@app.route('/nodes/get', methods=['GET'])

def get_nodes():

   nodes = list(blockchain.nodes)

   response = {'nodes': nodes}

return jsonify(response), 200

d7daa29240f74ef871fe48e83f96287c7d9dc6d0


结论

在此篇文章中,我们介绍了涉及区块链背后一些核心概念,并且学习如何用Python实现一个区块链。为了简单起见,此文没有涉及一些技术细节,例如:钱包地址和Merkle树。如果你想了解有关该主题的更多信息,我建议阅读比特币白皮书原著,并跟着比特币维基和Andreas Antonopoulos的优秀书籍学习:掌握比特币:编程开放区块链。


原文发布时间为:2018-04-4

本文作者:文摘菌

本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“大数据文摘”微信公众号

相关文章
|
1月前
|
算法 前端开发 数据处理
小白学python-深入解析一位字符判定算法
小白学python-深入解析一位字符判定算法
47 0
|
5天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
25 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
5天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
21 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
5天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
25 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
9天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
27 2
|
1月前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
134 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
1月前
|
存储 机器学习/深度学习 算法
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
蓝桥杯Python编程练习题的集合,涵盖了从基础到提高的多个算法题目及其解答。
60 3
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
|
1月前
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
142 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
19天前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
19 3
|
21天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
65 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型