Foundations of Blockchain
上QQ阅读APP看书,第一时间看更新

Blockchain functionality

The block linking process consists of several elements, such as creating a structure from the information, calculating the hash of the block, and appending it to the blockchain.

Let's break down each of these functionalities into blockchain methods:

class Blockchain(object): 
    """A class representing list of blocks""" 
 
    def __init__(self): 
 
        self._chain = [self.get_genesis_block()] 
        self.timestamp = int(datetime.now().timestamp()

The preceding class is a collection of class methods that create a valid blockchain using a hash function. The constructor of the Blockchain will initialize a chain by appending a genesis block, which is the first block of the blockchain, and doesn't have any reference to a previous block:

def get_genesis_block(self): 
    """creates first block of the chain""" 
 
    return Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"
)

A genesis block is a hardcoded block that is appended to the beginning of the blockchain. It is created with static contents. The preceding genesis block has a hardcoded hash value that is created using SHA-256, as follows:

SHA256.new(data=(str(0) + "0"+ str(1465154705) +"my genesis 
block!!").encode()).hexdigest() def calculate_hash(self, index, previous_hash, timestamp, data): """calculates SHA256 hash value""" hash_object = SHA256.new(data=(str(index) + previous_hash +
str(timestamp) + data).encode()) return hash_object.hexdigest()

calculate_hash is a crucial method in the blockchain because this method creates a hash value that binds all the blocks together. An SHA-256 hash value is created using the PyCryptodome package, as shown in the previous chapter. This method concatenates the block index, the hash value of the previous block, the timestamp, and the data required to create a string that needs to be hashed. The SHA256 hash function generates a digest that is the hash value of that block.

We need to find the hash value of the previous block during the creation of the next block. The following function identifies the last block appended to the chain:

def get_latest_block(self): 
    """gets the last block from the blockchain""" 
 
    try: 
        return self._chain[-1] 
    except IndexError as e: 
        return None 

The following function will build a block by constructing all the attributes that are required to create a Block object. It will also calculate the hash value for the current block. A new Block object consisting of the block structure will finally be created:

def create_block(self, block_data): 
    """creates a new block with the given block data""" 
 
    previous_block = self.get_latest_block() 
    next_index = previous_block.index + 1 
    next_timestamp = self.timestamp 
    next_hash = self.calculate_hash(next_index, 
previous_block.hash, next_timestamp, block_data) return Block(next_index, previous_block.hash, next_timestamp,
block_data, next_hash)
Note: We have created next_timestamp based on a static timestamp value that is created when the blockchain object is created. Although this is not true in an actual blockchain, we have done this intentionally to explain a particular case that will be explained during the code execution.

The following functions are used to add, reset, and read the blocks of the blockchain. The add_block method and the chain attribute are the only class members that need to be exposed to the user:

def add_block(self, data): 
    """appends a new block to the blockchain""" 
 
    self._chain.append(self.create_block(data)) 
 
@property 
def chain(self): 
    """created a dict containing list of block objects to view""" 
 
    return self.dict(self._chain) 
 
def dict(self, chain): 
    """converts list of block objects to dictionary""" 
 
    return json.loads(json.dumps(chain, default=lambda o: 
o.__dict__)) def reset(self): """resets the blockchain blocks except genesis block""" self._chain = [self._chain[0]]