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

简介:

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

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

而在本篇文章,抛开介绍区块链的技术特点和应用场景,文摘菌手把手的教大家如何用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

本文作者:文摘菌

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

相关文章
|
23天前
|
数据采集 机器学习/深度学习 数据可视化
【优秀python web系统毕设】基于python的全国招聘数据分析可视化系统,包括随机森林算法
本文介绍了一个基于Python的全国招聘数据分析可视化系统,该系统利用数据挖掘技术、随机森林算法和数据可视化技术,从招聘网站抓取数据,进行处理、分析和预测,帮助用户洞察招聘市场,为求职者和企业提供决策支持。
|
23天前
|
搜索推荐 前端开发 数据可视化
【优秀python web毕设案例】基于协同过滤算法的酒店推荐系统,django框架+bootstrap前端+echarts可视化,有后台有爬虫
本文介绍了一个基于Django框架、协同过滤算法、ECharts数据可视化以及Bootstrap前端技术的酒店推荐系统,该系统通过用户行为分析和推荐算法优化,提供个性化的酒店推荐和直观的数据展示,以提升用户体验。
|
1天前
|
数据可视化 物联网 区块链
探索Python中的数据可视化:使用Matplotlib和Seaborn绘制图表探索未来:区块链、物联网与虚拟现实的融合趋势与应用前景
【8月更文挑战第30天】本文旨在引导读者通过Python编程语言,利用Matplotlib和Seaborn库,轻松掌握数据可视化技术。文章以浅显易懂的语言,结合实用的代码示例,从基础的图表绘制到高级定制功能,逐步深入讲解如何在数据分析中运用这些工具。无论你是编程新手还是希望提升可视化技能的开发者,都能在这篇文章中找到有价值的信息,让你的数据“活”起来。
|
23天前
|
机器学习/深度学习 数据采集 算法
【优秀python算法毕设】基于python时间序列模型分析气温变化趋势的设计与实现
本文介绍了一个基于Python的时间序列模型,用于分析和预测2021-2022年重庆地区的气温变化趋势,通过ARIMA和LSTM模型的应用,揭示了气温的季节性和趋势性变化,并提供了对未来气温变化的预测,有助于气象预报和相关决策制定。
【优秀python算法毕设】基于python时间序列模型分析气温变化趋势的设计与实现
|
5天前
|
算法 JavaScript 前端开发
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
50 1
|
14天前
|
网络协议 安全 Unix
6! 用Python脚本演示TCP 服务器与客户端通信过程!
6! 用Python脚本演示TCP 服务器与客户端通信过程!
|
18天前
|
编解码 算法 Linux
Linux平台下RTSP|RTMP播放器如何跟python交互投递RGB数据供视觉算法分析
在对接Linux平台的RTSP播放模块时,需将播放数据同时提供给Python进行视觉算法分析。技术实现上,可在播放时通过回调函数获取视频帧数据,并以RGB32格式输出。利用`SetVideoFrameCallBackV2`接口设定缩放后的视频帧回调,以满足算法所需的分辨率。回调函数中,每收到一帧数据即保存为bitmap文件。Python端只需读取指定文件夹中的bitmap文件,即可进行视频数据的分析处理。此方案简单有效,但应注意控制输出的bitmap文件数量以避免内存占用过高。
|
17天前
|
传感器 数据采集 算法
python实现ModBusRTU客户端方式
python实现基于串口通信的ModBusRTU客户端是一件简单的事情,只要通过pymodbus模块就可以实现。
|
19天前
|
JSON 算法 API
京东以图搜图功能API接口调用算法源码python
京东图搜接口是一款强大工具,通过上传图片即可搜索京东平台上的商品。适合电商平台、比价应用及需商品识别服务的场景。使用前需了解接口功能并注册开发者账号获取Key和Secret;准备好图片的Base64编码和AppKey;生成安全签名后,利用HTTP客户端发送POST请求至接口URL;最后解析JSON响应数据以获取商品信息。
|
18天前
|
算法 Python
python多继承的3C算法是什么?怎么用?
有很多地方都说python多继承的继承顺序,是按照深度遍历的方式,其实python多继承顺序的算法,不是严格意义上的深度遍历,而是基于深度遍历基础上优化出一种叫3C算法
下一篇
云函数