An interpretation of blockchain and a simple Python implementation

Concept of interpretation

Blockchain has been known to almost everyone in a few days, and this term also aroused my strong interest. However, after searching online and reading from many sources, I found that many literatures introducing blockchain were either ambiguous or the authors themselves had limited understanding, leading to unclear description of many key issues. I spent some time summing up, hoping to give readers a more comprehensive and clear understanding.

Blockchain is officially defined as a distributed ledger, a technical solution that collectively maintains a reliable database in a decentralized, untrusted way. So how to understand outsiders? Below I will describe in detail the generation process and implementation significance of a blockchain, so as to build a clear concept of blockchain for everyone. We’ll start with principles, then features, then uses, then code, and you’ll feel like you’ve seen the light of day.

Let’s take BTC as an example: “blockchain”, as its name implies, is a chain composed of successively connected blocks. It can be likened to an infinite length straight iron chain, and each iron ring is a block. So what should the contents of the block be? There are two kinds of block in narrow sense, one is ordinary block, one is creation block. Creation chain block is a block in the project the first block, because individual level is limited, not done detailed research on genesis blocks, but according to my understanding, the foundation block should be have similar to ordinary block structure, but will certainly add some founders want to say something, and in some projects may be a record, the more is the circulation of coin, For example, the 600 billion number of SWTC is written in the Trands block and cannot be modified once issued.

So what exactly is in an ordinary block?

  1. Index: is the number from 0 to n, can be called the chain height.
  2. Hash: a random 256-bit number that is the unique number of this block.
  3. Previous hash: the hash of the previous block. A normal block has and only one previous hash. That’s why a blockchain is called a chain.
  4. Tempstamp: Used to record the birth of the block.
  5. Difficulty: Visually illustrates the difficulty of creating the block.
  6. Nonce: random number used to generate the next block.

All of the above exists in the block header.

  1. Data: Records of stored transactions. Only this exists in the block body.

Ok, there are a few basic elements that a block should have, and you’re probably in a state of confusion right now: How exactly does this stuff work? I’ll take a step by step look at how blockchain works, but first ask two questions: Why are new blocks created? How do I create new blocks?

Why the new fast?

As mentioned before, a block record is a bill, which stores several transaction records, which is the most powerful proof of the specific activities of the buyer and the seller. For example, our purchase record on Taobao is our consumption bill. People’s Daily consumption records are constantly growing and cannot be kept in one block forever, so what is the difference from the current centralized storage mechanism? So, as the number of buying and selling records continues to increase, new blocks need to be created constantly to store this data.

How do I create new blocks?

I believe that in addition to blockchain, the word “mining” should be heard a lot recently. Mining is actually the process by which miners create new blocks. In BTC projects, BTC miners are rewarded with a certain amount of BTC for successfully mining (in other words, successfully creating a block), so the amount of BTC is gradually increased within a certain range. In blockchain projects that are generally allowed to mine (there are also blockchain projects that limit the number of coins not allowed to mine), the number of miners will generally be greater than 6, and new blocks approved by more than 6 miners can be added to the blockchain. At this point, some say: Wow! BTC’s worth so much, isn’t mining fun? In fact, if the block increases rapidly without limit, it will cause great problems. According to the setting of Satoshi nakamoto, the whole network can only produce a new block every 10 minutes at present. And this 10 minutes is not calculated by their own pinch table, the generation of new blocks is a lot of calculation, this 10 minutes is someone else’s pre-design, so that the calculation of large to the whole network 10 minutes can generally only produce one.

Ok, so far, the basic concept of blockchain has been introduced almost, let’s get down to business, talk about the block workflow:

1. If A wants to make A deal with B, for example, A transfers A BTC to B, B will pay RMB 10W to A. A will first send its BTC source information and traders to B, and at the same time make A copy to the whole network. What? Is there any privacy in that? Of course, smart cong cong will not make such a low-level mistake. In a blockchain, each individual transaction (or network node) has a pair of public and private keys. The public key acts as a “payment address,” while the private key is a 256-digit number that identifies itself and is currently typically generated using SHA265, so that no one knows who the parties are. Send a message, the sender using a hash function generated from the message text message digest, then use your own private key to encrypt the summary will serve as a message encrypted digital signature with message sent to the receiver, the receiver first with the same hash function as the sender from the received message digest calculated in the original message, The sender’s public key is then used to decrypt the digital signature attached to the packet. If the two digests are the same, the receiver can confirm that the digital signature belongs to the sender.

2. Is the deal done at this point? If this is done, what is the difference between A directly delivering 10W cash to B by parcel? At this point, all miners in the network will get the transaction record, and all miners in the network will start to create blocks for some reward. The miners will use the hash function to generate a unique 256-digit number for the block, but this number is not simply generated randomly. The number is uniquely determined according to the specific content of the block, such as transaction content and nonce. In other words, the number corresponding to two blocks with the same content must be unique. But what of it, you ask? It’s not that hard. Wrong! In order to control the block generation time, so that the block generation rate meets the standard of every 10 minutes of the whole network, developed a strict block generation verification rules, that is to say, can generate a successful block depends on whether your number conforms to this rule. For example, the first N bits of the generation number must be 0.

Since the transaction content of a block cannot be modified, miners can only try this function by modifying the Nonce until a successful block is generated. If the average block generation time becomes faster or slower, the system will adjust the block verification rules accordingly, so that the average block generation time can be controlled within the specified range.

If a miner completes a block, the other miners will be informed immediately. If the other miners do not complete the generation of a new block at this time, they will stop their work and verify the block. The information to be confirmed is mainly as follows:

  • The block number is valid; This simply puts the block into the hash function to see if the resulting number matches the number in the block.

  • The preceding block of the block is valid; As mentioned earlier, blocks are connected in series. Each ordinary block records the number of the previous block, which requires other miners to compare the last block of the current blockchain to see if it is the same.

  • The transaction list is valid; That is, to verify whether A has this BTC to give to B. In the transaction information of block chain, the past and present of all BTC in the transaction will be recorded. Block chain can trace back to the source, so where and why each BTC is here can be clearly seen, so this is no problem.

When a new block is verified, the whole network will consider the block valid, add it to the end of the existing block chain, and at the same time end the mining work for the block, put into the next mining cycle.

3. However, it is not hard to imagine that there is a hidden danger of conflict in such a mechanism. It is just a coincidence that two miners make a correct block at the same time, so there is no need to choose one or the other, and the original linear block chain can be changed into a tree:

But this will lead to the addition of corresponding blocks after A and B in the future, so whoever is longer will continue as the main chain, and the other may be gradually forgotten, unless it becomes longer.

Well, that’s the basics of blockchain, and now it’s time to talk about the pros and cons.

Nothing in the world can be called perfect. Just like blockchain, although it has been labeled as capable of subverting the future, it still has its limitations: 1. Timeliness. It is easy to find that there are many verification and delivery links in blockchain, which leads to its poor timeliness. 2, energy consumption, this is also obvious, blockchain requires a lot of useless computing to control the generation time of the block. So blockchain is not suitable for highly time-sensitive networks.

As for the advantages of blockchain, such as security, decentralization and so on have been clearly described on the network, I will not repeat them here. Next I’ll use a piece of Python code to implement a simple mining process.


Code sample

First create a class that represents the blockchain:

class BlockChain:
    def __init__(self, initialHash):
        # init block chain
        self.chain = []

        # init pitman
        self.pitmen = []
        for i in range(6):
            self.pitmen.append(Pitman)

        # collect mine results
        self.results = []

        # generate GenesisBlock
        self.new_block(initialHash)
Copy the code


Here’s a look at blockchain-type methods:

@property
def last_block(self):
    if len(self.chain):
        return self.chain[-1]
    else:
        return None
Copy the code


ef get_trans(self):
   return json.dumps({
       'sender': ' '.join(random.sample(string.ascii_letters + string.digits, 8)),
       'recipient': ' '.join(random.sample(string.ascii_letters + string.digits, 8)),
       'amount': random.randrange(1, 10000)
   })
Copy the code


def new_block(self, initialHash=None):
    if initialHash:
        # generate Genesis Block
        block = Block()
        block.index = 0
        block.nonce = random.randrange(0, 99999)
        block.previousHash = '0'
        block.difficulty = 0
        block.transactionData = self.get_trans()
        guess = f'{block.previousHash}{block.nonce}{block.transactionData}'.encode()
        block.hash = hashlib.sha256(guess).hexdigest()
        block.time = time()
        self.chain.append(block)
    else:
        for i in range(len(self.pitmen)):
            pm = MyThread(target=self.pitmen[i].mine,
                                  args=(self.pitmen[i],
                                        len(self.chain),
                                        self.last_block.get_block()['Hash'],
                                        self.get_trans()))
            pm.start()
            pm.join()
            self.results.append(pm.get_result())

        # show all blocks
        print("All blocks generated by pitmen:")
        for result in self.results:
            print(result[0].get_block())

        # get new block
        firstblock = self.results[0][0]
        mintime = Decimal(self.results[0][1])
        for i in range(1, len(self.results)):
            if Decimal(self.results[i][1]) < mintime:
                firstblock = self.results[i][0]
            else:
                continue
        self.chain.append(firstblock)
        self.results = []
Copy the code


This is the core part of the block generation, this method is mainly divided into two parts: according to the transmission of parameters to distinguish whether the genesis block, if the need is a genesis block, then automatically generated by the type of block to occupy the first position of the block chain. If a normal block needs to be generated, some basic information is distributed to the miners for mining operations. So I’ve got six miners here, and just to be fair, I’ve also got a multithreading going on here to try to keep them all informed so that they can dig at the same time. Normally, the first successful miner would send the information to the other miners, and the other miners would immediately stop the verification. However, due to the limited time, I did not realize this step of verification. Here, I allow all miners to complete their work and submit the work and the corresponding work time, and the blocks that take the shortest time to generate will be added to the blockchain as the correct blocks. In essence, it also follows the principle of “fast first” blockchain generation.


After all that talk, what does the inside of the block look like?

class Block:
    def __init__(self):
        self.index = None
        self.time = None
        self.difficulty = None
        self.nonce = None
        self.hash = None
        self.previousHash = None
        self.transactionData = None

    def get_block(self):
        return {
            'Index': self.index,
            'Time': self.time,
            'Difficulty': self.difficulty,
            'Hash': self.hash,
            'Nonce': self.nonce,
            'PreviousHash': self.previousHash,
            'TransactionData': self.transactionData
        }
Copy the code


After all, miners are the producers and promoters of blockchain, and their position is the core. In the miner class, I designed two methods, a mine method, which generates a new block and returns the length of time it took to generate the block.

def mine(self, index, previousHash, transactionData):
    beginTime = time()

    block = Block()
    block.index = index
    block.previousHash = previousHash
    block.transactionData = transactionData
    block.difficulty, block.hash, block.nonce = self.generate_hash(previousHash, transactionData)
    block.time = time()
    endTime = time()

    return block, endTime - beginTime
Copy the code


I set up a block chain of length 6. Since the first block is the creation block, the actual block creation starts with the second block. Note index.

This is the first block completed by six miners:

All blocks generated by pitmen:
{'Index': 1, 'Time': 1516268156.5971138.'Difficulty': 2.'Hash': '01f505a276e3f55a868d9ee18f70bcff75429e1de70f5ab59471a3551cc67a30'.'Nonce': 91554, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "OY8z0Rrx", "recipient": "iSGFJsEm", "amount": 8723}'}
{'Index': 1, 'Time': 1516268156.5971138.'Difficulty': 5, 'Hash': 'c3ba406bad0d87f816f629830a15e2997638bfa230484c224e5470eaa24d8790'.'Nonce': 62372, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "9o8UMDLe", "recipient": "qTOQu7kv", "amount": 2746}'}
{'Index': 1, 'Time': 1516268156.5981123.'Difficulty': 5, 'Hash': '8ff243885e9017296aa2ef1a611ef5b3927ddce818cb7255a04ff3228c982c60'.'Nonce': 67644, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "kIqy1c8C", "recipient": "WSdK0EXh", "amount": 9329}'}
{'Index': 1, 'Time': 1516268156.5981123.'Difficulty': 3.'Hash': 'ff9716bf9379e2ab7a8640419e7c7b7c7329a5e6e1bbf83a1249f49d070ca8b0'.'Nonce': 37336, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "vBwU0luH", "recipient": "d7o6cRCj", "amount": 5628}'}
{'Index': 1, 'Time': 1516268156.5981123.'Difficulty': 3.'Hash': '3410c70c31f9bacbfcbd74d63f25f69f27d36075e2d44bddaa60bd72fa042e60'.'Nonce': 34617, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "yzcNpBnh", "recipient": "vbIr7SKo", "amount": 6387}'}
{'Index': 1, 'Time': 1516268156.5981123.'Difficulty': 27, 'Hash': '91e3dc3ef1a151557a1edd837528410b916362bcfb77dbb14dc54c8929f5a0d0'.'Nonce': 49121, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "p1MguhVz", "recipient": "gVSom4D3", "amount": 7356}'}
Copy the code





A final look at the overall blockchain result:

{'Index': 0.'Time': 1516268156.5971138.'Difficulty': 0.'Hash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'Nonce': 87688, 'PreviousHash': '0'.'TransactionData': '{"sender": "OuVCmHbs", "recipient": "kFxbwSLc", "amount": 503}'}
{'Index': 1, 'Time': 1516268156.5971138.'Difficulty': 2.'Hash': '01f505a276e3f55a868d9ee18f70bcff75429e1de70f5ab59471a3551cc67a30'.'Nonce': 91554, 'PreviousHash': '7532402844a1c130833a27600298d09a007d6124603cf44be9c05fcd5428c34a'.'TransactionData': '{"sender": "OY8z0Rrx", "recipient": "iSGFJsEm", "amount": 8723}'}
{'Index': 2.'Time': 1516268156.5991132.'Difficulty': 4.'Hash': '098544436793881e8041c0c903c96c0055e16396113d73c63bc55e7ba78ec130'.'Nonce': 12875, 'PreviousHash': '01f505a276e3f55a868d9ee18f70bcff75429e1de70f5ab59471a3551cc67a30'.'TransactionData': '{"sender": "HJZSX1hk", "recipient": "j82k51yY", "amount": 3521}'}
{'Index': 3.'Time': 1516268156.6001143.'Difficulty': 27, 'Hash': '7c10243223caf39bc5a6067de8d93f6ea46bad62c4a0fbcc0aa4e086585d8200'.'Nonce': 18663, 'PreviousHash': '098544436793881e8041c0c903c96c0055e16396113d73c63bc55e7ba78ec130'.'TransactionData': '{"sender": "cJrGxN5R", "recipient": "wkZI8QCv", "amount": 1224}'}
{'Index': 4.'Time': 1516268156.601114.'Difficulty': 3.'Hash': '60a099d3fe53e031800669fcc1d9b5ab6df1f80a40354135310a799892f1c3d0'.'Nonce': 51446, 'PreviousHash': '7c10243223caf39bc5a6067de8d93f6ea46bad62c4a0fbcc0aa4e086585d8200'.'TransactionData': '{"sender": "nCNJoy52", "recipient": "kYBT9f65", "amount": 3603}'}
{'Index': 5, 'Time': 1516268156.605163.'Difficulty': 2.'Hash': '765f69163cf95584721015e3ce819c1980ce33752f8a4dea553d3bedd39f8920'.'Nonce': 31804, 'PreviousHash': '60a099d3fe53e031800669fcc1d9b5ab6df1f80a40354135310a799892f1c3d0'.'TransactionData': '{"sender": "FqOkiTEu", "recipient": "y9EDcSYA", "amount": 4185}'}
Copy the code


That’s the end of what I want to say. In the end, I want to say that blockchain is a magical technology, which has deeply attracted me from hearing it. I hope that blockchain can really bring great changes in the future. To know, with the rise of AI, the advent of blockchain, the digital era of programmers will be further sublimated, the Internet era is just the beginning! Thank you for reading. My level is limited. If you find any problems or deviations in my understanding, please point them out in time. The full code is attached at the end of the article.

import hashlib
import random
import string
import json
import threading
from decimal import Decimal
from time import time


class MyThread(threading.Thread):

    def __init__(self, target, args=()):
        super(MyThread, self).__init__()
        self.func = target
        self.args = args

    def run(self):
        self.result = self.func(*self.args)

    def get_result(self):
        try:
            return self.result
        except Exception:
            return None


class BlockChain:
    def __init__(self, initialHash):
        # init block chain
        self.chain = []

        # init pitman
        self.pitmen = []
        for i in range(6):
            self.pitmen.append(Pitman)

        # collect mine results
        self.results = []

        # generate GenesisBlock
        self.new_block(initialHash)

    @property
    def last_block(self):
        if len(self.chain):
            return self.chain[-1]
        else:
            return None

    def get_trans(self):
        return json.dumps({
            'sender': ' '.join(random.sample(string.ascii_letters + string.digits, 8)),
            'recipient': ' '.join(random.sample(string.ascii_letters + string.digits, 8)),
            'amount': random.randrange(1, 10000)
        })

    def new_block(self, initialHash=None):
        if initialHash:
            # generate Genesis Block
            block = Block()
            block.index = 0
            block.nonce = random.randrange(0, 99999)
            block.previousHash = '0'
            block.difficulty = 0
            block.transactionData = self.get_trans()
            guess = f'{block.previousHash}{block.nonce}{block.transactionData}'.encode()
            block.hash = hashlib.sha256(guess).hexdigest()
            block.time = time()
            self.chain.append(block)
        else:
            for i in range(len(self.pitmen)):
                pm = MyThread(target=self.pitmen[i].mine,
                                      args=(self.pitmen[i],
                                            len(self.chain),
                                            self.last_block.get_block()['Hash'],
                                            self.get_trans()))
                pm.start()
                pm.join()
                self.results.append(pm.get_result())

            # show all blocks
            print("All blocks generated by pitmen:")
            for result in self.results:
                print(result[0].get_block())

            # get new block
            firstblock = self.results[0][0]
            mintime = Decimal(self.results[0][1])
            for i in range(1, len(self.results)):
                if Decimal(self.results[i][1]) < mintime:
                    firstblock = self.results[i][0]
                else:
                    continue
            self.chain.append(firstblock)
            self.results = []

    def show_chain(self):
        print('This is mine first block chain! ')
        for block in self.chain:
            print(block.get_block())


class Block:
    def __init__(self):
        self.index = None
        self.time = None
        self.difficulty = None
        self.nonce = None
        self.hash = None
        self.previousHash = None
        self.transactionData = None

    def get_block(self):
        return {
            'Index': self.index,
            'Time': self.time,
            'Difficulty': self.difficulty,
            'Hash': self.hash,
            'Nonce': self.nonce,
            'PreviousHash': self.previousHash,
            'TransactionData': self.transactionData
        }


class Pitman:

    def mine(self, index, previousHash, transactionData):
        beginTime = time()

        block = Block()
        block.index = index
        block.previousHash = previousHash
        block.transactionData = transactionData
        block.difficulty, block.hash, block.nonce = self.generate_hash(previousHash, transactionData)
        block.time = time()
        endTime = time()

        return block, endTime - beginTime

    @staticmethod
    def generate_hash(previousHash, transactionData):
        difficulty = 0
        nonce = random.randrange(0, 99999)
        guess = f'{previousHash}{nonce}{transactionData}'.encode()
        myhash = hashlib.sha256(guess).hexdigest()
        whilemyhash[-1] ! ='0':
            difficulty += 1
            nonce += difficulty
            guess = f'{previousHash}{nonce}{transactionData}'.encode()
            myhash = hashlib.sha256(guess).hexdigest()
        return difficulty, myhash, nonce


if __name__ == '__main__':
    chain = BlockChain(1)
    length = 5
    for i in range(length):
        chain.new_block()
    chain.show_chain()
Copy the code

Read on: Blockchain Quantitative Investment Series – Dynamic Balancing Strategies