来源 | BlockChange
区块链作为比特币和其他加密货币的核心技术,在最近几年引起了全世界的注意,但是各国这一颠覆性的技术态度不一,因为其去中心化的分布式结构,可以使用户之间直接进行交流,无需中心节点参与的这种技术模式对银行、证券等机构带来了极大影响。
我们实现的区块链有如下几个特性:
我们的区块链客户端有如下几个功能:
我们还实现了2个展示界面:
我在原始代码的基础上进行了一些改动,向交易中加入了RSA加密,并实现了钱包生成和交易加密,两个界面使用HTML/CSS/JS 实现。
完整的项目代码:
https://github.com/adilmoujahid/blockchain-python-tutorial
请注意,这个实现是用于教学目的,所以它不适用于生产环境。因为它保密性不够,且缺乏一些重要的特性。
区块链客户端实现
你可以从终端启动区块链客户端。进入blockchain_client文件夹,并输入命令:python blockchain_client.py。
在浏览器中打开http://localhost:8080,接下来你会看到如下展示界面。
展示界面导航栏有3个标签:
要想生成交易或查看交易,至少需要一个区块链节点在运行(将在下一节中介绍)。
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
下面我们定义一个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
区块链的实现
你可以从终端启动区块链节点,通过进入blockchain文件夹,并输入命令:python blockchain_client.py或python blockchain_client.py -p <PORT NUMBER> 。如果你未指定端口号,则会默认端口号为5000。在浏览器中打开http://localhost:<PORT NUMBER>可以看到区块链前端展示界面。
展示界面导航栏有两个标签:
下面是blockchain.py文件代码中一些重要部分的说明。
我们首先定义一个具有以下属性的Blockchain类:
这个Blockchain类还实现了以下方法:
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' 作为输入,并且如果签名有效,则将交易添加到将添加到下一个块的交易列表中。
@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
下面我们定义Flask 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
结论
在此篇文章中,我们介绍了涉及区块链背后一些核心概念,并且学习如何用Python实现一个区块链。为了简单起见,此文没有涉及一些技术细节,例如:钱包地址和Merkle树。如果你想了解有关该主题的更多信息,我建议阅读比特币白皮书原著,并跟着比特币维基和Andreas Antonopoulos的优秀书籍学习:掌握比特币:编程开放区块链。
原文链接:
http://adilmoujahid.com/posts/2018/03/intro-blockchain-bitcoin-python/?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website
本文分享自微信公众号 - 量化投资与机器学习(ZXL_LHTZ_JQXX),作者:Adil Moujahid
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2018-04-04
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句