本篇教程是面向各能力层级的 Python 开发者介绍区块链(blockchain)。你将通过从零实现一个公链(public blockchain)和构建一个简单的应用来确切理解区块链到底是什么。

你将会使用 Flask 轻量级框架为区块链的不同功能创建端点,然后在多个机器上运行代码来创建一个去中心化网络(decentralized network)。同时你还将构建一个能与区块链相交互的简单的用户界面并存储任何种信息,好比点对点支付、聊天或是电子商务。

Python 是一种易懂的编程语言,这也是我在这选择它的原因。一个完整的纯 Python 编写的简单应用代码,你都可以在 Github 上看到。

首先要知道Python 编程的基础;

了解 REST-APIs;

熟悉 Flask(非强制的,熟悉最好)。

背景

2008 年一本名为 Bitcoin: A Peer-to-Peer Electronic Cash System 的白皮书由一个叫做 Satoshi Nakamoto 的个人(或是团体)发布。其中结合了多种的加密技术和点对点网络,将支付变得无需中心权威(就像银行)参与,名为比特币的加密货币也诞生了。除了比特币,其中也同样介绍了一个用于存储数据的分布式系统(现在最为熟知的就是区块链),它的适用性要远比支付与加密货币大得多。

从那时起,区块链几乎引起了各个行业的兴趣。区块链现在也是数字加密货币像比特币、分布式计算技术像以太坊(Ethereum)还有一些开源框架像 Hyperledger Fabric 及架构在其上的 IBM 区块链平台的底层技术。

什么是区块链 blockchain?

区块链是一种存储数字数据(digital data)的方式。数据可以是任何东西,对于比特币来说,数据就是交易(用户间比特币的转移记录),数据也可以是文件;没什么。数据以区块的形式被存储,并且被以加密哈希的方式连接(或链接)起来 —— 因此得名区块链。

所有的魔力都在于数据的存储与添加到区块链上的方式。区块链本质上是有序数据的链表,也有下面几个约束:区块一旦添加便无法修改,换句话说区块只能被添加;

数据的添加有着明确的规则;

其架构是分布式的。

这些约束的强制实施又会产生下面的好处 :数据的不可变性和持久性;

无单点控制或故障;

数据添加顺序的可验证审计追踪(A verifiable audit trail of the order in which data was added)。

那么那些约束又是如何实现这些特性的呢?你将在实现区块链的过程中学到更多,让我们开始吧。

关于这个应用

让我们先来简单定义一下这个迷你应用的范围。我们的目标是构建一个允许用户发布共享信息的应用,因此,内容将会被存储在区块链中同时也是持久存在的。用户可以通过一个简单的 web 界面来交互 。将交易(transaction)存储在区块中;

为区块添加数字指纹;

链接区块;

实现工作量证明的算法;

将区块添加到链;

创建界面;

建立共识与去中心化;

编译应用;

运行应用。

我们将使用自下而上的方法来实现,来从定义区块链中的数据存储结构开始吧。一个 post 就是由我们应用中的任何用户发布的一个信息,post 将包含下面的三个必要元素:内容 content

发布者 author

时间戳 timestamp

1. 将交易(transaction)存储在区块中

我们将以 JSON 这种广泛使用的格式来将数据存储在我们的区块链中,下面是一个 post 存储在区块链中的链子:

{

"author": "some_author_name",

"content": "Some thoughts that author wants to share",

"timestamp": "The time at which the content was created"

}

通用术语 ”数据(data)“ 在网上经常被术语 “事务(transaction)” 所替代,所以为了避免困惑并保持一致性,我们将开始在事例程序中使用术语事务来指代数据。

事务被打包在区块当中,一个区块可以包含一个或多个事务。包含事务的区块会频繁的生成并被添加到区块链上,因为有着多个区块所以每个块都有着唯一的 ID:

class Block:

def __init__(self, index, transactions, timestamp):

"""Constructor for the `Block` class.:param index: Unique ID of the block.:param transactions: List of transactions.:param timestamp: Time of generation of the block."""

self.index = index

self.transactions = transactions

self.timestamp = timestamp

2. 为区块添加数字指纹

我们想要防止存储在区块中的数据遭到各种篡改,而探测是其第一步。你可以使用加密哈希函数 来探测区块中的数据是否遭到了篡改。

哈希函数会从输入的任意长度数据中生产出固定大小的数据(哈希),这通常用于标识输入。理想的哈希函数特征是 :易于计算;

结果确定,这意味着同一个数据总是产生同一哈希结果;

均匀随机,这意味着即使一个比特的改变都会显著改变原始数据的哈希。

其结果是:几乎不可能从给定的哈希猜测出输入数据(唯一的方法是尝试全部的可能输入组合);

如果你同时知道输入与哈希,那你可以轻易地通过哈希函数来验证其哈希。

这为不对称所做出的努力 —— 要求轻易地从输入数据中获得哈希与几乎不可能从哈希中得出输入数据,正是区块链想要获得的特性。

哈希函数有很多种,这里 Python 的例子中使用的是 SHA-256 哈希函数 :

>>> from hashlib import sha256

>>> data = b"Some variable length data"

>>> sha256(data).hexdigest()

'b919fbbcae38e2bdaebb6c04ed4098e5c70563d2dc51e085f784c058ff208516'

>>> sha256(data).hexdigest() # no matter how many times you run it, the result is going to be the same 256 character string

'b919fbbcae38e2bdaebb6c04ed4098e5c70563d2dc51e085f784c058ff208516'

>>> data = b"Some variable length data2" # Added one character at the end.

'9fcaab521baf8e83f07512a7de7a0f567f6eef2688e8b9490694ada0a3ddeec8'

# Note that the hash has changed entirely!

我们将区块的哈希存储在我们的 Block 对象内部的字段中,这就像是其中包含的数据的数字指纹(或签名)。

from hashlib import sha256

import json

def compute_hash(block):

"""Returns the hash of the block instance by first converting itinto JSON string."""

block_string = json.dumps(self.__dict__, sort_keys=True)

return sha256(block_string.encode()).hexdigest()

注意 :在多数加密货币中,甚至是区块中独立的事务都经过了哈希处理并被存储为哈系树的形式(也称为 merkle tree),其树根通常是区块的哈希。这不是区块链的必要功能,为保持简单而被我们忽略了。

3. 链接区块

我们已经建立了区块,区块链应该是区块的集合。我们可以通过 Python 的列表来存储所有的区块,但这还是不够的,因为如果有人故意用新块替换了集合中的旧区块该怎么办?对于上述的实现方式来说,创建一个修改过事务的区块并计算其哈希,然后替换掉一个旧区块并不是件难事。

我们需要一种任何对已有区块的改变都会使整条链失效的方法,比特币的方法是通过某区块与其紧之前区块的哈希来链接彼此,这样便在连续的区块中创建了一种依赖。这里说到的链接,是要在当前区块的 previous_hash 字段中包含其紧之前区块的哈希。

好了,如果每个区块都通过在 previous_hash 字段中包含前一个区块的哈希来链接,那第一个块该怎么办?第一个区块被称为创世区块(genesis block)它可以手工或通过独特的逻辑来生成。我们来为 Block 类加上 previous_hash 字段并且实现 Blockchain 类的初始结构。

from hashlib import sha256

import json

import time

class Block:

def__init__(self, index, transactions, timestamp, previous_hash):

"""Constructor for the `Block` class.:param index: Unique ID of the block.:param transactions: List of transactions.:param timestamp: Time of generation of the block.:param previous_hash: Hash of the previous block in the chain which this block is part of."""

self.index = index

self.transactions = transactions

self.timestamp = timestamp

self.previous_hash = previous_hash # Adding the previous hash field

def compute_hash(self):

"""Returns the hash of the block instance by first converting itinto JSON string."""

block_string = json.dumps(self.__dict__, sort_keys=True)

# The string equivalent also considers the previous_hash field now

return sha256(block_string.encode()).hexdigest()

class Blockchain:

def __init__(self):

"""Constructor for the `Blockchain` class."""

self.chain = []

self.create_genesis_block()

def create_genesis_block(self):

"""A function to generate genesis block and appends it tothe chain. The block has index 0, previous_hash as 0, anda valid hash."""

genesis_block = Block(0, [], time.time(), "0")

genesis_block.hash = genesis_block.compute_hash()

self.chain.append(genesis_block)

@property

def last_block(self):

"""A quick pythonic way to retrieve the most recent block in the chain. Note thatthe chain will always consist of at least one block (i.e., genesis block)"""

return self.chain[-1]

现在,如果之前任何区块中的内容有改变:先前区块的哈希将会发生改变;

这将会导致其后一块中的 previous_hash 字段不匹配;

由于对输入数据的哈希计算中包含着 previous_hash 字段,对下一区块计算的哈希又会随之改变。

最终,被替换过区块后的整条链都将失效,而唯一的修复办法是重新计算整条链。

4. 实现工作量证明的算法

还有一个问题,如果我们修改了先前区块,之后全部区块的哈希都可以被轻易的重新计算出来,以便生成一个不同的有效链。为避免其发生,我们可以利用之前讨论过的哈希函数的不对称性来使计算哈希这个任务变得困难与随机。我们可以这样做:不去接受区块的任何哈希,而是为它添加一些限制。限制是:其哈希应该由 ”n 个前导 0“ 开始,n 可以是任意正整数。

我们知道除非我们改变区块的数据,否则哈希是不会变得,当然我们也不想改变已经存在的数据。那我们该怎么办?很简单!我们来添加一些可以改变的虚假数据。在我们的 block 类中添加一个新的字段 nonce。nonce 是一个我们可以不断修改的数字,直至得到满足约束的哈希。约束条件的满足起到了对某些算力已经执行了的证明作用,这种技巧其实是比特币中使用的 Hashcash 算法的简化版。约束中被指定的零的个数决定了我们工作量证明算法的难度(零的个数越多就越难计算。)

还有,由于不对称性,工作量证明是很难计算的可一旦你算出了 nonce 便会很容易验证(你只需要再运行一次哈希函数即可。):

class Blockchain:

# difficulty of PoW algorithm

difficulty = 2

"""Previous code contd.."""

def proof_of_work(self, block):

"""Function that tries different values of the nonce to get a hashthat satisfies our difficulty criteria."""

block.nonce = 0

computed_hash = block.compute_hash()

while not computed_hash.startswith('0' * Blockchain.difficulty):

block.nonce += 1

computed_hash = block.compute_hash()

return computed_hash

注意,其实是没有快速计算 nonce 的逻辑,仅仅只有强力计算,唯一明确的提升是你可以使用专门被设计来计算哈希函数的有较少 CPU 指令的硬件芯片。

5. 将区块添加到链

为了将区块添加到链中,我们将首先验证如下:数据未经篡改(工作量证明是正确的);

事务的顺序被保留(待添加区块的 previous_hash 字段指向链中最新区块的哈希)。

下面是将区块添加到链的代码:

class Blockchain:

"""Previous code contd.."""

def add_block(self, block, proof):

"""A function that adds the block to the chain after verification.Verification includes:* Checking if the proof is valid.* The previous_hash referred in the block and the hash ofa latest block in the chain match."""

previous_hash = self.last_block.hash

if previous_hash != block.previous_hash:

return False

if not Blockchain.is_valid_proof(block, proof):

return False

block.hash = proof

self.chain.append(block)

return True

def is_valid_proof(self, block, block_hash):

"""Check if block_hash is valid hash of block and satisfiesthe difficulty criteria."""

return (block_hash.startswith('0' * Blockchain.difficulty) and

block_hash == block.compute_hash())

挖矿

事务最开始会存储为未经确认的事务池,将未经确认的事务放入区块中和计算工作量的过程被熟知为挖矿(mining)。一旦有 nonce 满足了我们的约束,我们便可说是有一个区块被挖出了并且它可以被加到区块链上了。

在大多数的加密货币中(包括比特币),矿工都可以获得一定量的加密货币的奖赏,以作为他们花费算力计算工作量证明的报酬。我们的挖矿函数看起来是这样的:

class Blockchain:

def __init__(self):

self.unconfirmed_transactions = []

# data yet to get into blockchain

self.chain = []

self.create_genesis_block()

"""Previous code contd..."""

def add_new_transaction(self, transaction):

self.unconfirmed_transactions.append(transaction)

def mine(self):

"""This function serves as an interface to add the pendingtransactions to the blockchain by adding them to the blockand figuring out proof of work."""

if not self.unconfirmed_transactions:

return False

last_block = self.last_block

new_block = Block(index=last_block.index + 1,

transactions=self.unconfirmed_transactions,

timestamp=time.time(),

previous_hash=last_block.hash)

proof = self.proof_of_work(new_block)

self.add_block(new_block, proof)

self.unconfirmed_transactions = []

return new_block.index

6. 创建界面

现在我们该来为我们的区块链节点创建界面以与我们的应用相交互,我们将用一个 Python 流行的框架 Flask 创建 REST API 来实现对区块链节点的交互与调用各种函数。如果你之前曾了解过任何一种 web 框架,那么看懂下面的代码对你来说都不是难事。

from flask import Flask, request

import requests

# Initialize flask application

app = Flask(__name__)

# Initialize a blockchain object.

blockchain = Blockchain()

我们需要一个端点来为应用提交事务,这也被我们的应用程序向区块链添加新数据(post)所 需要:

# Flask's way of declaring end-points

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

def new_transaction():

tx_data = request.get_json()

required_fields = ["author", "content"]

for field in required_fields:

if not tx_data.get(field):

return "Invalid transaction data", 404

tx_data["timestamp"] = time.time()

blockchain.add_new_transaction(tx_data)

return "Success", 201

下面的端点用于返回链中节点的副本,我们的应用也是需要此端点来显示所有要查询的数据:

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

def get_chain():

chain_data = []

for block in blockchain.chain:

chain_data.append(block.__dict__)

return json.dumps({"length": len(chain_data),

"chain": chain_data})

下面的端点用于请求节点来挖掘未确认的事务(如果有的话),我们将用它初始化一个命令用来在我们的应用中进行挖矿:

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

def mine_unconfirmed_transactions():

result = blockchain.mine()

if not result:

return "No transactions to mine"

return "Block #{} is mined.".format(result)

@app.route('/pending_tx')

def get_pending_tx():

return json.dumps(blockchain.unconfirmed_transactions)

这些 REST 风格的端点将在我们的区块链上用来创建事务与挖矿。

7. 建立共识与去中心化

目前为止,我们所创建的区块链都是运行在单个计算机上的。即使我们链接起来了区块并且都应用了工作量证明约束,但我们还是不能信任单个节点(这里指的就是单个计算机)。我们需要数据是分布式的,我们需要多个节点来维护区块链。所以从单节点到点对点网络(peer-to-peer network)转换的第一步是,创建一种能使新加入的节点意识到网络中其他节点的机制。

# Contains the host addresses of other participating members of the network

peers = set()

# Endpoint to add new peers to the network

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

def register_new_peers():

# The host address to the peer node

node_address = request.get_json()["node_address"]

if not node_address:

return "Invalid data", 400

# Add the node to the peer list

peers.add(node_address)

# Return the blockchain to the newly registered node so that it can sync

return get_chain()

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

def register_with_existing_node():

"""Internally calls the `register_node` endpoint toregister current node with the remote node specified in therequest, and sync the blockchain as well with the remote node."""

node_address = request.get_json()["node_address"]

if not node_address:

return "Invalid data", 400

data = {"node_address": request.host_url}

headers = {'Content-Type': "application/json"}

# Make a request to register with remote node and obtain information

response = requests.post(node_address + "/register_node",

data=json.dumps(data), headers=headers)

if response.status_code == 200:

global blockchain

global peers

# update chain and the peers

chain_dump = response.json()['chain']

blockchain = create_chain_from_dump(chain_dump)

peers.update(response.json()['peers'])

return "Registration successful", 200

else:

# if something goes wrong, pass it on to the API response

return response.content, response.status_code

def create_chain_from_dump(chain_dump):

blockchain = Blockchain()

for idx, block_data in enumerate(chain_dump):

block = Block(block_data["index"],

block_data["transactions"],

block_data["timestamp"],

block_data["previous_hash"])

proof = block_data['hash']

if idx > 0:

added = blockchain.add_block(block, proof)

if not added:

raise Exception("The chain dump is tampered!!")

else: # the block is a genesis block, no verification needed

blockchain.chain.append(block)

return blockchain

一个新的节点加入到网络之中将会调用 register_with_existing_node() 方法(通过 /register_with 端点)来注册成为网络中的现存节点。这将有助于以下几点:要求远程节点将新的点(peer)添加到已知列表中;

用远程节点上的区块链初始化新节点上的区块链;

如果节点脱离网络,重新连接后便会重新同步。

然而多节点当中还有一个问题,由于一些蓄意操作或是意外(如网络延迟)将导致某些节点对链的拷贝是不同的。这种情况下众多节点需要就选用链的某版本达成一致,以维持整个系统的完整性。换句话说,我们需要实现共识(consensus)。

当网络中的参与节点对链表现出不同时,一种简单的共识算法是让节点都以最长的合法链为准。这个方法背后的基本原理是,将最长合法链看作是耗费掉大部分工作量的(记得工作量证明是很难计算的):

class Blockchain

"""previous code continued..."""

def check_chain_validity(cls, chain):

"""A helper method to check if the entire blockchain is valid."""

result = True

previous_hash = "0"

# Iterate through every block

for block in chain:

block_hash = block.hash

# remove the hash field to recompute the hash again

# using `compute_hash` method.

delattr(block, "hash")

if not cls.is_valid_proof(block, block.hash) or \

previous_hash != block.previous_hash:

result = False

break

block.hash, previous_hash = block_hash, block_hash

return result

def consensus():

"""Our simple consensus algorithm. If a longer valid chain isfound, our chain is replaced with it."""

global blockchain

longest_chain = None

current_len = len(blockchain.chain)

for node in peers:

response = requests.get('{}/chain'.format(node))

length = response.json()['length']

chain = response.json()['chain']

if length > current_len and blockchain.check_chain_validity(chain):

# Longer valid chain found!

current_len = length

longest_chain = chain

if longest_chain:

blockchain = longest_chain

return True

return False

接下来,我们要开发出当一个节点挖到一个区块时能在网络中进行宣告的方法,以便让其他节点能更新他们的区块链并且转向挖掘新的事务。其他区块将能简单地进行验证工作量证明,并且将挖到的区块添加到其各自的链上(要记得一旦 nonce 被发现了验证就是很简单的事了):

# endpoint to add a block mined by someone else to

# the node's chain. The node first verifies the block

# and then adds it to the chain.

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

def verify_and_add_block():

block_data = request.get_json()

block = Block(block_data["index"],

block_data["transactions"],

block_data["timestamp"],

block_data["previous_hash"])

proof = block_data['hash']

added = blockchain.add_block(block, proof)

if not added:

return "The block was discarded by the node", 400

return "Block added to the chain", 201

def announce_new_block(block):

"""A function to announce to the network once a block has been mined.Other blocks can simply verify the proof of work and add it to theirrespective chains."""

for peer in peers:

url = "{}add_block".format(peer)

requests.post(url, data=json.dumps(block.__dict__, sort_keys=True))

announce_new_block() 方法应该在每一个区块被挖掘出后被调用,以便于节点能把它添加到链上。

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

def mine_unconfirmed_transactions():

result = blockchain.mine()

if not result:

return "No transactions to mine"

else:

# Making sure we have the longest chain before announcing to the network

chain_length = len(blockchain.chain)

consensus()

if chain_length == len(blockchain.chain):

# announce the recently mined block to the network

announce_new_block(blockchain.last_block)

return "Block #{} is mined.".format(blockchain.last_block.index

8. 编译应用

现在是时候处理我们应用程序的界面了,我们使用了 Jinja2 模板来渲染网页还有一些 CSS 都让它看起来更票了一些。

我们的应用需要连接到网路中的一个节点来获取数据与提交数据,链接多个节点也是可以的。

# Node in the blockchain network that our application will communicate with

# to fetch and add data.

CONNECTED_NODE_ADDRESS = "http://127.0.0.1:8000"

posts = []

fetch_posts() 函数将从节点的 /chain 端点获取数据、解析数据并存储在本地。The fetch_posts function gets the data from the node’s /chain endpoint, parses the data, and stores it locally.

def fetch_posts():

"""Function to fetch the chain from a blockchain node, parse thedata, and store it locally."""

get_chain_address = "{}/chain".format(CONNECTED_NODE_ADDRESS)

response = requests.get(get_chain_address)

if response.status_code == 200:

content = []

chain = json.loads(response.content)

for block in chain["chain"]:

for tx in block["transactions"]:

tx["index"] = block["index"]

tx["hash"] = block["previous_hash"]

content.append(tx)

global posts

posts = sorted(content,

key=lambda k: k['timestamp'],

reverse=True)

我们的应用有一个 HTML 表格来处理用户输入,并且之后会向连接的节点发出一个 POST 请求,来向未验证的事务池中添加一个事务。事务接着会在网络中被挖掘,最终一旦我们刷新页面便会获取到数据:

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

def submit_textarea():

"""Endpoint to create a new transaction via our application"""

post_content = request.form["content"]

author = request.form["author"]

post_object = {

'author': author,

'content': post_content,

}

# Submit a transaction

new_tx_address = "{}/new_transaction".format(CONNECTED_NODE_ADDRESS)

requests.post(new_tx_address,

json=post_object,

headers={'Content-type': 'application/json'})

# Return to the homepage

return redirect('/')

9. 运行应用

克隆下来:

git clone https://github.com/satwikkansal/python_blockchain_app.git

安装依赖:

cd python_blockchain_app

pip install -r requirements.txt

启动一个区块链节点服务:

export FLASK_APP=node_server.py

flask run --port 8000

我们的一个区块链节点的实例已经启用来了,并且运行在 8000 端口上。

在另一个终端会话上运行我们的应用:

python run_app.py

10. 多节点运行

你若想通过分离多个自定义节点进行操作,就要用 register_with/ 端点来在现存的对等网络中注册一个新节点。

这或许是一个你想尝试的简单方案:

# already running

# flask run --port 8000 &

# spinning up new nodes

flask run --port 8001 &

flask run --port 8002 &

你可以使用下面的 curl 请求来在已经运行的 8000 上注册 8001 和 8002 的节点:

curl -X POST \ http://127.0.0.1:8001/register_with \ -H 'Content-Type: application/json' \ -d '{"node_address": "http://127.0.0.1:8000"}'

curl -X POST \ http://127.0.0.1:8002/register_with \ -H 'Content-Type: application/json' \ -d '{"node_address": "http://127.0.0.1:8000"}'

这将会让 8000 端口上的节点了解到 8001 和 8002 端口上的节点,反之亦然。新节点也会跟链中的现存节点做同步,以便他们能积极参与到挖矿中。

要变更与我们应用前台同步的节点(默认的是 8000 端口),只需要改变 views.py 文件中的 CONNECTED_NODE_ADDRESS 项即可。

一旦你都做了上面的步骤,你就可以运行应用(python run_app.py)并创建事务了(在 web 界面进行 post),接着当你挖到事务时网络中的所有节点都将更新链。每个节点的链也能通过 curl 调用 /chain 端点进行检查。

curl -X GET http://localhost:8001/chain

curl -X GET http://localhost:8002/chain

11. 事务验证

你可能已经发现了应用中的一个不足:任何人都可以用任何名字发布任何内容。还有,在向区块链网络提交事务的时候发布易受干扰。一种解决办法是为用户创建公钥私钥加密算法,每个新用户都需要一个公钥和一个私钥才能在我们的应用内进行发布。密钥是用来创建和验证数字前面的,以下是其工作原理:每一个事务的提交都会被用户私钥签名,该签名会作为用户信息的一部分附加到事务的数据当中;

在个验证阶段,当挖掘事务时我们可以验证所说的拥有者是否与事务数据中指定的拥有者相同,以及信息是否被篡改过。这可以通过发布者的签名以及他的公钥完成。

结论

这篇教程覆盖到了公有区块链的基础只是,如果你一路跟了下来,你应该有能力从零实现一个区块链并且构建一个允许用户在其上分享信息的简单应用了。这个实现不像是其他共有区块链像是比特币或以太坊那样精致 —— 但如果你能对你的每个需求问对问题的话,你终将成功的。你得知道在设计一个能满足你需求的区块链中最关键的一事,是融会贯通计算机科学当中的现有知识,就这一件。

手机编写python挖矿_用 Python 从零开发一个区块链应用相关推荐

  1. python做客户端适合吗_太简单!只学十分钟,Python菜鸟也能开发一个区块链客户端...

    原标题:太简单!只学十分钟,Python菜鸟也能开发一个区块链客户端 作者:Adil Moujahid 编译:kou.Eli 本文转自区块链大本营(ID:blockchai_camp),转载需授权 区 ...

  2. python开发一个区块链只需40多行

    40多行python代码开发一个区块链?可信吗?我们将通过Python 2动手开发实现一个迷你区块链来帮你真正理解区块链技术的核心原理.python开发区块链的源代码保存在Github. 尽管有人认为 ...

  3. 太简单!只学十分钟,Python菜鸟也能开发一个区块链客户端

     区块链技术以其去中心化特性成为又一具有颠覆性特征的技术.Python作为一种面向对象的解释型计算机程序设计语言,因其具有丰富和强大的库,常被称为"胶水语言",简单.易上手,是区 ...

  4. 40行python开发一个区块链

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 尽管有人认为区块链目前还是个不成熟的解决方案,但它无疑称得上是计算机发展历史上的一个奇迹.但是,到底区块链是什么呢? 我 ...

  5. 如何用 Python 快速开发一个区块链数据结构?

    作者 | arjuna sky kok 整理 | Aholiab 出品 | 区块链大本营(blockchain_camp) 根据IEEE此前的一项调查,Python已成为最受开发者欢迎的语言之一.由于 ...

  6. 福州python招聘_【Python程序员招聘|Python程序员最新招聘信息】-看准网

    立即投递 职位薪资:6000-10000 经验:不限 学历:不限 类型:全职 linux下python编程 对接ai平台做应用 立即投递 职位薪资:8000-13000 经验:不限 学历:本科 类型: ...

  7. 第一章 第一节:Python基础_认识Python

    Python基础入门(全套保姆级教程) 第一章 第一节:Python基础_认识Python 1. 什么是编程 通俗易懂,编程就是用代码编写程序,编写程序有很多种办法,像c语言,javaPython语言 ...

  8. linux保存python文件_告诉Python将.txt文件保存到Linux上的某个目录 - python

    我试图将文件保存在QCTestFiles目录中,但是我的脚本未将文件写入指定的目录中.我的路径文件是否适用于Linux,如果不是,我如何更改代码以在另一个目录中写入和保存文件?我当前的脚本在brper ...

  9. python区块链框架_从零开始创建一个区块链应用(Python版)

    2018年什么最火?非区块链莫属! 一时间网上各种介绍区块链的文章层出不穷,但大多数都是从概念层面进行解释的,本文则从技术层面讲解,如何从零开始创建一个区块链应用. 本文使用Python开发,读者需要 ...

最新文章

  1. 集中荷载matlab程序,电力系统负荷预报的matlab实现.doc
  2. OpenCV的滑块与回调函数
  3. mysql-8.0.14-winx64,mysql-8.0.15-winx64 解压版安装教程及退出的三种方式
  4. hibernate.cfg.xml hibernate 配置文件模板
  5. 共享两个做项目最常用功能操作的封装类
  6. “70后”清华教授,任大学校长
  7. 卡通形象医疗病毒细菌宣传海报模板,psd分层,方便应用!
  8. python socket.error: [Errno 10054] 远程主机强迫关闭了一个现有的连接。问题解决方案
  9. 【Java】使用URL类访问互联网资源
  10. java获取时间日期代码
  11. codevs 1766 装果子
  12. 南阳理工acm1043高数
  13. 亿图图示上线小程序,MindMaster移动端迎来大更新,亿图软件八周年再出发
  14. 命令查看windows2008是否激活
  15. VScode开发PHP的必要插件
  16. 数据结构与算法实验01-使用链表实现多项式乘法
  17. 安装Vue-cli并且创建项目
  18. ubuntu 下最简单的歌词软件osdlyric (with banshee)
  19. 远程桌⾯连接电脑后键盘失灵解决方案
  20. Ada 程序设计语言(The Ada Programming Language)[第一集]

热门文章

  1. SAP中BOM事务清单CS13中的物料数量单位逻辑梳理及格式调整处理实例
  2. Properties类,InetAddress类,网络编程,反射,Mysql数据库
  3. Python decimal模块的使用
  4. SMT贴片加工生产流程
  5. 一天4个个人记录,哇嘎嘎
  6. 中级Android面试总结之Android篇
  7. druid spring监控配置
  8. 为喜欢的人撰写最深情的生日祝福语
  9. 知乎问答怎样做?知乎问答营销技巧干货
  10. FreeRTOS检测堆栈溢出方法