Tendermint + Python tutorial - developing your own blockchain
Part 1 - Wallet

This article is the first from the series dedicated to the development of blockchain with Tendermint. It will be of interest to all those who is interested in creating a blockchain network and has to choose one of many different options. Objectively, Tendermint currently has many rivals: Exonum proposed by the BitFury team, HyperLedger Fabric made by Linux Foundation and many others. Strengths and weaknesses of every instrument will be discussed in a separate article, and here we will simply state the main point: Tendermint is incredibly easy to use. This framework probably guarantees the most comfort start for the development of corporate blockchains, especially in the case of MVPs.

We use Tendermint for over a year already; we developed blockchains for four different projects and really enjoy this instrument. This series of articles will describe the general philosophy of working with Tendermint (this part will be interesting for non-tech people) and the development tutorial.

This series will be resulted in a fully working cryptocurrency. You can already research the final result in our Github repo – https://github.com/SoftblocksCo/Simple_coin


On its own, Tendermint can be described as a certain core that includes the most necessary functionality, characteristic of any blockchain. It can be said that the task of Tendermint is to free the developers from the too routine tasks. Here is a simple example: every blockchain network is decentralized by definition. It means that when you mount a node of Bitcoin, Ethereum etc., your node immediately starts to look for other members of the network. Without giving any special attention to the mechanism hidden under the hood, we shall remark that this functionality of “seeking one’s equals” should be implemented in the software of every blockchain project.

But there are already hundreds of different blockchains in the world, and this task is implemented by each and every one of them. Does it mean that if you face a need to develop your own blockchain, your developers will have to strive once again for a solution that should long be OOB?

If you decide to use Tendermint, there will be no such need. This project enables the developers to spend their time describing the business logic of your blockchain, not some routine things. Here is the approximate list of what you get right out of the box:

  • The consensus algorithm (it is easily customized but we shall discuss it another time)
  • P2P networking
  • Memory pool
  • API (very handy, for the creation of some third-party software such as wallets etc.)

Let us say few words about the architecture of Tendermint. In essence, it consists of two main components: Tendermint core and Application. I already told about the Tendermint core above. The Application is an implementation of your business logic. We shall consider an example to make it easier. Let us have two participants: Alice node and Bob node. Every node (from the software point of view) corresponds to a pair of Tendermint core and Application. When Alice creates a transaction (for instance, with the help of a wallet), she addresses her Tendermint core – “This is a new transaction, please distribute it over the network”.

As we already said earlier, the Tendermind core assumes all the tasks of finding other members of the network and communicating with them. For us it is important that the Tendermint core from Bob’s node received this transaction after some time. Now a question arises: is this transaction valid? Perhaps there was a mistake and Alice sent him more money than she had? This is when your Application kicks in.

As a matter of fact, the Tendermint core does not have any idea of your blockchain – about its tasks, limitations, protocol etc. For the Tendermint core, any transaction is nothing but a combination of bytes. It can send them to other nodes, it can remember that such transaction already happened. By contrast, it is not interested in the questions of logic. Instead of this, receiving a transaction, it would contact your Application and ask: “This is the transaction 0x…. Is it valid?”. However, inside your Application, you would have to carry out all the necessary checks and “answer” to the core – yes or no.

As you can see, one more advantage of Tendermint is its incredible modularity. You implement one component that should “answer a range of questions” from the Tendermint core – and that is all! In addition, the interaction between the Tendermint core and Application works through ABCI protocol call. It means that if you know how to work with this protocol, nothing stops you from using any programming language to write the Application. In general, there are no limitations on the used stack of development.

Probably the most popular question asked by our customers is about the productivity of Tendermint. In these recent times, the talks about 100 / 1,000 / 5,000 transactions per second are no longer considered crazy so we will clarify this issue. The best idea would be to quote Tendermint’s own dоcuments:

“Tendermint blocks can commit to finality in the order of 1 second. Tendermint can handle transaction volume at the rate of 10,000 transactions per second for 250byte transactions. The bottleneck is in the application.”

In a nutshell, it means that Tendermint core itself has a bandwidth of up to 10,000 transactions per second. And the bandwidth of your blockchain will probably depend on the implementation of your Application.


The description of Tendermint for general public is over. Now we will speak about the development based on Tendermint. We used Ubuntu 16.04 for the development and deployment. We chose Python as a language to write our Application. The use of Go is recommended (it is in this language that the Tendermint core is written) but we chose Python for our tutorial because it is known to a larger number of people.

To work with the Tendermint core, we will use docker containers. The data written in the blockchain will be lost in the case of removal of the container, so it is advisable to save the data on the host computer (flagged –v):

sudo docker run --rm -v /your/tendermint/folder:/tendermint tendermint/tendermint:0.24.0 

Configuring the Python environment

As it often happens in the world of Python solutions, whether a technology is fresh or not, there are already several libraries for it. We shall use tm-abci; this wrapper represents the basic class `BaseApplication` that can process the requests coming from Tendermint core and call the methods you implemented. This wrapper is maintained by the Softblocks team – if you have any troubles or suggestions, feel free to create the Issues or Pull requests in our repo.

cd Simple_coin
virtualenv --python python3 --no-site-packages venv/
source venv/bin/activate
pip install -r requirements.txt


As an example, we will implement a most simple cryptocurrency. By simplicity we mean a full absence of specific features such as smart contracts, oracles, zero-knowledge and so on. The whole functionality of our coin can be described by the following list:

– A user can have a wallet (at the output, the user will get a private and a public key);
– A user can send another user coins (to do this, the public key of the recipient is required);
– A user can record a text line in the transaction (a kind of data storage).


First of all, let us sort out the protocol and the cryptography that we would use. As we do not aim to create anything capable of making it into a top position on coinmarketcap.com, we can take the liberty to make some simplifications. I suggest employing the so-called state model used by Ethereum, and the transactions themselves will be implemented as a common JSON.

We will call a transaction the following data structure:

    "sender" : ,
    "receiver" : ,
    "amount" : 100,
    "data" : "big espresso",
    "timestamp" : 1517395993,
    "signature" :

As you can see, it is JSON, completely familiar to us, using the public keys of the sender and the recipient as their addresses. The field ‘amount’ shows the amount of the transaction, ‘data’ preserve some additional data, and ‘timestamp’ is used to preserve the timestamp of the transaction. The ‘signature’ will also include the signature of the transaction by the private key of the sender, but we will discuss it in more detail below.

Opening an account

As you already understood, private and public keys are required to work with our coin. We chose Ed25519 as a standard for cryptographic signatures. In general, any other standard could be used, for instance secp256k1, used in Bitcoin and its forks. But, to begin with, Tendermint uses Ed25519 under the hood. Secondly, Ed25519 does have some advantages as compared to Bitcoin. You can find a detailed description of these two standards in the Exonum blog.

We will provide a short review for those who are absolutely not familiar with such cryptography. First of all, the user will need a private key, consisting of 32 random bytes = 256 random bits. To work with cryptography, we will use the ed25519 package. As a wallet, let us use files with the extension .sc: the private key is written in the first line, the public key in the second line.

signing_key, verifying_key = ed25519.create_keypair(entropy=urandom)
with open(options.wallet, "w") as ff:

To make creating a new address handier, we implement a new flag in wallet.py: -n / –new

$ python wallet.py --new --wallet my.sc
New keypair saved into the my.sc
$ cat my.sc

Signing the message

This function is not essential but we decided to build it in order to demonstrate in layman’s terms how the electronic signing works. Using the flag –sign, we can sign any message, for instance: “Hello, world”:

$ python wallet.py --message "Hello world" --sign
The signature is: JHCfU2rJ4sm9GGfXRo9tBWoVJ5/MGW+B4MhFzapIR6bS46saPLNQVz00drmR52ZwgdzjDX0647HYXCFMpFgpCA

Verifying the message signature

Let us now make sure that our signature works correctly. We can check it with the help of the flag check_sign (the public key is taken from my.sc file):

$ python wallet.py --check_sign JHCfU2rJ4sm9GGfXRo9tBWoVJ5/MGW+B4MhFzapIR6bS46saPLNQVz00drmR52ZwgdzjDX0647HYXCFMpFgpCA --message "Hello world" --pub_key 0ADti7wLQBWj0SlPTkwmegrydF1LtuSTYUw1d00bpt4
Valid signature!

Great, the signature passed the test! Let us now try to modify the first character of the signature J -> I:

$ python wallet.py --check_sign IHCfU2rJ4sm9GGfXRo9tBWoVJ5/MGW+B4MhFzapIR6bS46saPLNQVz00drmR52ZwgdzjDX0647HYXCFMpFgpCA --message "Hello world" --pub_key 0ADti7wLQBWj0SlPTkwmegrydF1LtuSTYUw1d00bpt4
Invalid signature!

Predictably, the signature did not pass the test. Perfect, now we have a working instrument for signing the transactions.

Creation of transaction

First of all, let us create the recipient for our transaction (we shall call the recipient Bob).

$ python wallet.py --new --wallet bob.sc
New keypair saved into the bob.sc
$ cat bob.sc

Let us now create a transaction. We wish to send Bob 10 coins and send him a message: “Thanks for latte”:

$ python wallet.py --transaction --amount 10 --receiver nSQkpxrkWfdjFKVzvbLkbJd6oTIWXPmdudHYJMjVcqo --data "Thanks for latte" --wallet my.sc
Your txn is printed bellow. Copy as it is and send with the ABCI query

Signature of the transaction

The transaction is signed automatically, when it is created, but let us examine this process in more detail. To verify the authenticity of the transaction, we will sign every transaction with the private key of the sender. As we remember, the public key of the sender will be featured in the transaction so its authenticity will be easy to check.

        txn = {
           "sender" : verifying_key.to_ascii(encoding="base64").decode(),
           "receiver" : options.receiver,
           "amount" : options.amount,
           "data" : options.data,
           "timestamp" : int(time())

To verify the conformity of the signature to the message, we should be sure that the verifying side will receive the same message. In Python, the dictionaries do not guarantee a regular order of keys so we will sign the line that consists of the transaction fields separated with an ‘;’

       keys_sequence = sorted(txn.keys())
       msg_to_sign = ";".join([str(txn[k]) for k in keys_sequence])
       txn["signature"] = signing_key.sign(msg_to_sign.encode(), encoding="base64").decode("ascii")

Broadcasting the transaction

To send one’s transaction to the network, one can use the standard API, build in Tendermint. The issues of working with Tendermint core will be discussed in the next article, and here I will only provide an example of how the interaction with API looks:

       r = requests.get("http://localhost:26657/broadcast_tx_async?tx={}".format(options.broadcast))
       if r.status_code == 200:
           txn_hash = r.json()['result']['hash']
           exit("Txn broadcasted, txn hash: {txn_hash}".format(txn_hash))
           err_log = r.json()['result']['log']
           exit("Can't broadcast your txn: {err_log}".format(err_log))

Getting balance

To пуе the current balance of a user (or, to be more exact, of a public key), we need a functioning blockchain so we will implement this command in the next part of the article.


In this article, we primarily tried to describe the main idea of Tendermint. Other instruments for the creation of one’s own blockchain can be said to follow a similar philosophy overall. However, according to our impressions and our experience, Tendermint is an undisputed leader in such nominations as accessibility, and quickness and ease of development. In our next article, we will implement business logic on the base of Tendermint and test the functioning of our coin.

If you still have any questions, do not hesitate to ask them in our Twitter or send to the sergey@softblocks.co!

Close Menu