A blockchain toy project, in Python
Project description
toychain
toychain is a very simplistic blockchain node modeling in Python.
While the code is my own adaptation, the implementation is from the very good tutorial by Daniel van Flymen.
This adaptation uses FastAPI
as a web framework, and uvicorn
as ASGI server instead of the Flask
app from van Flymen's tutorial.
Running
This repository uses Poetry
as a build tool.
Get a local copy through VCS and to set yourself up with poetry install
.
The poetry run node
command is predefined to start up a node, by default at localhost:5000
.
Additionally, you can specify the host and port on which to run the node with the --host
and --port
flags.
You can then use the same command to spin up several nodes on different ports.
Docker
It is possible to run nodes as docker containers.
To do so, clone the repository then build the image with docker build -t blockchain .
You can then run the container by mapping the node's port to a desired one at localhost
on your machine.
To map the node to port 5000, run:
$ docker run --init --rm -p 5000:5000 blockchain
To emulate additional nodes, vary the public port number:
$ docker run --init --rm -p 5001:5000 blockchain
$ docker run --init --rm -p 5002:5000 blockchain
$ docker run --init --rm -p 5003:5000 blockchain
You can then play around by POSTing to /nodes/register
to add all your running instances to one another's networks, POSTing transactions, mining new blocks, and resolving the blockchain.
Functionality
The Chain
The blockchain is a simple list of blocks.
A block
in the chain consists of a dictionnary with the following keys:
- the
index
at which it is located in the chain, - a
timestamp
of when the block was added to the chain, - the list of
transactions
recorded in the block, - the
proof
of validity for itself, - a
previous_hash
tag referencing the hash of the previous block in the chain, for immutability.
A simple example block (with a single transaction) as a json payload would look like this:
block = {
"index": 1,
"timestamp": 1506057125.900785,
"transactions": [
{
"sender": "8527147fe1f5426f9dd545de4b27ee00",
"recipient": "a77f5cdfa2934df3954a5c7c7da5df1f",
"amount": 5,
}
],
"proof": 324984774000,
"previous_hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}
The Node Implementation
The blockchain functionality is provided by a single class, BlockChain
, in the toychain.blockchain
module.
An instance of the BlockChain
class is used to run a node.
Each node stores a full blockchain, the current transactions (not yet written in the chain), and the list of other nodes in the network.
It can:
- Add a transaction to the list of current transactions,
- Add a new (validated) block to the chain,
- Run the proof of work algorithm (here simple, for the sake of computation time),
- Validate the
proof
of a block, - Register other nodes on the network,
- Infer an arbitrary node's blockchain's validity,
- Resolve conflict through a consensus algorithm, checking all nodes' chains in the network and adopting the longest valid one.
A node is ran as a REST API using the FastAPI
web framework, and is attributed a UUID
at startup.
The implementation is in the toychain.node
module, and the available endpoints of a node are:
GET
endpoint/mine
to trigger the addition of a new block to the chain,POST
endpoint/transactions/new
to add a transaction to the node's list,GET
endpoint/chain
to pull the full chain,POST
endpoint/nodes/register
to register other nodes' addresses as part of the network,GET
endpoint/nodes/resolve
: to trigger a run of the consensus algorithm and resolve conflicts: the longest valid chain of all nodes in the network is used as reference, replacing the local one, and is returned.
Once the server is running (for instance with python -m toychain
), an automatic documentation for those is served at the /docs
and /redoc
endpoints.
Let's consider our node is running at localhost:5000
.
POSTing a transaction to the node's transactions/new
endpoint with cURL would be done as follows:
curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "someone-other-address",
"amount": 5
}' "http://localhost:5000/transactions/new"
Let's now consider that we have started a second node at localhost:5000
.
POSTing a payload to register this new node to the first one's network with cURL would be done as follows:
curl -X POST -H "Content-Type: application/json" -d '{
"nodes": ["http://127.0.0.1:5001"]
}' "http://localhost:5000/nodes/register"
If you would rather use httpie
, those commands would be, respectively:
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file toychain-0.2.0.tar.gz
.
File metadata
- Download URL: toychain-0.2.0.tar.gz
- Upload date:
- Size: 8.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.0.5 CPython/3.7.6 Darwin/19.5.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 373e0afd92fd9c04ae9ceecf9b265b1635c4b56f4996f73fb35dbc94854fc4d1 |
|
MD5 | cc0acc11718d8ee43fba1436f3010f5c |
|
BLAKE2b-256 | ebb3da6ce069a67351910eac116a60727f16efc206c42c9aff31ed4d183610c6 |
Provenance
File details
Details for the file toychain-0.2.0-py3-none-any.whl
.
File metadata
- Download URL: toychain-0.2.0-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.0.5 CPython/3.7.6 Darwin/19.5.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 95a584f69d319b57e16e0558d0e5db7006632c799e86daa0a44759fd9c7c1cad |
|
MD5 | 8bc16dc5e8bc09ae082ad7032b0d9251 |
|
BLAKE2b-256 | a02fd63856e30ed34ef4390dfc8bd4d916da937de8631d5544eef59f50acb5bf |