一个用Python实现的区块链玩具项目
项目描述
toychain
toychain是一个用Python实现的非常简化的区块链节点建模。虽然代码是我的改编,但实现来自Daniel van Flymen非常好的教程。这个改编使用FastAPI
作为Web框架,使用uvicorn
作为ASGI服务器,而不是van Flymen教程中的Flask
应用。
运行
此存储库使用Poetry
作为构建工具。通过VCS获取本地副本,然后使用poetry install
进行设置。
预定义的poetry run node
命令用于启动节点,默认在localhost:5000
。此外,您可以使用带有--host
和--port
标志的命令指定要运行节点的主机和端口。然后,您可以使用相同的命令在不同的端口上启动多个节点。
Docker
可以以Docker容器运行节点。为此,克隆存储库,然后使用docker build -t blockchain .
构建镜像。
然后,您可以通过将节点的端口映射到您的机器上localhost
的期望端口来运行容器。要将节点映射到端口5000,请运行
$ docker run --init --rm -p 5000:5000 blockchain
为了模拟额外的节点,更改公共端口号
$ docker run --init --rm -p 5001:5000 blockchain
$ docker run --init --rm -p 5002:5000 blockchain
$ docker run --init --rm -p 5003:5000 blockchain
然后,您可以通过向/nodes/register
发送POST请求来添加所有运行实例到彼此的网络中,通过POST事务,挖掘新的区块,并解决区块链。
功能
链
区块链是一个简单的区块列表。区块链中的一个区块
由以下键的字典组成
- 在链中的
索引
位置, - 区块被添加到链中的
时间戳
, - 记录在区块中的
交易
列表, - 自身有效性的
证明
, - 一个指向链中前一个区块哈希的
previous_hash
标签,用于不可变性。
一个简单的区块示例(包含一个交易),作为一个JSON有效载荷,看起来是这样的
block = {
"index": 1,
"timestamp": 1506057125.900785,
"transactions": [
{
"sender": "8527147fe1f5426f9dd545de4b27ee00",
"recipient": "a77f5cdfa2934df3954a5c7c7da5df1f",
"amount": 5,
}
],
"proof": 324984774000,
"previous_hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}
节点实现
区块链功能由toychain.blockchain
模块中的一个名为BlockChain
的单个类提供。使用BlockChain
类的实例来运行一个节点。每个节点存储完整的区块链、当前交易(尚未写入链中)和网络中其他节点的列表。它可以
- 将交易添加到当前交易列表中,
- 将一个新的(验证过的)区块添加到链中,
- 运行工作量证明算法(这里简单,为了计算时间),
- 验证区块的
证明
, - 注册网络上的其他节点,
- 推断任意节点的区块链的有效性,
- 通过共识算法解决冲突,检查网络中所有节点的链,并采用最长有效链。
节点作为使用FastAPI
网络框架的REST API运行,并在启动时分配一个UUID
。实现位于toychain.node
模块中,节点的可用端点如下
GET
端点/mine
用于触发向链中添加新区块,POST
端点/transactions/new
用于将交易添加到节点的列表中,GET
端点/chain
用于拉取完整链,POST
端点/nodes/register
用于将其他节点的地址注册为网络的一部分,GET
端点/nodes/resolve
:用于触发共识算法的运行和解决冲突:使用网络中所有节点的最长有效链作为参考,替换本地链,并返回。
一旦服务器启动(例如使用python -m toychain
),将在/docs
和/redoc
端点提供自动文档。
假设我们的节点正在运行在localhost:5000
。使用cURL将交易POST到节点的transactions/new
端点如下
curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "someone-other-address",
"amount": 5
}' "http://localhost:5000/transactions/new"
现在假设我们已经启动了一个第二个节点在localhost:5000
。使用cURL将有效载荷POST到注册这个新节点到第一个节点的网络中如下
curl -X POST -H "Content-Type: application/json" -d '{
"nodes": ["http://127.0.0.1:5001"]
}' "http://localhost:5000/nodes/register"
如果您想使用httpie
,相应的命令分别是
echo '{ "sender": "d4ee26eee15148ee92c6cd394edd974e", "recipient": "someone-other-address", "amount": 5 }' | http POST http://localhost:5000/transactions/new
echo '{ "nodes": ["http://127.0.0.1:5001"] }' | http POST http://localhost:5000/nodes/register
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。