Engee documentation
Notebook

Implementation of a simple blockchain in Julia language

In this example, we implement a simplified algorithm for blockchain, the technology underlying cryptocurrencies, distributed ledgers, and data security.

Introduction

A blockchain is a distributed database consisting of interconnected blocks. Each block contains data, a timestamp, and a cryptographic hash of the previous block. This makes the structure protected from fakes and changes: if someone tries to change the data in one of the blocks, they will change its hash, which will affect all subsequent blocks.

In this example, we implement:

  • the block structure,
  • block hash generation,
  • building a block chain,
  • checking the integrity of the chain.

This is a simplified version of the blockchain, but it shows the key principles of its operation.

The main part

Installing and connecting the necessary packages

Installing the SHA package needed to calculate hashes

In [ ]:
import Pkg; Pkg.add("SHA")
   Resolving package versions...
    Updating `~/.project/Project.toml`
  [ea8e919c] + SHA v0.7.0
    Updating `~/.project/Manifest.toml`
  [ea8e919c] + SHA v0.7.0

Connecting the SHA package, which allows you to calculate SHA-256 hashes

In [ ]:
using SHA

Defining the block structure

Data structure Block it represents a single block in the blockchain.
Contains:

  • index: block number in the chain
  • timestamp: block creation time
  • data: data stored in the block
  • previous_hash: hash of the previous block
  • hash: custom block hash
In [ ]:
struct Block
    index::Int
    timestamp::Float64
    data::String
    previous_hash::String
    hash::String
end
Out[0]:
Block

A function for generating a block hash

Function calculate_hash generates a SHA-256 hash based on the block data.
Parameters:

  • index: block number
  • timestamp: creation time
  • data: content of the block
  • previous_hash: hash of the previous block
In [ ]:
function calculate_hash(index, timestamp, data, previous_hash)
    # Combining the block data into one line
    block_data = string(index, timestamp, data, previous_hash)
    # Calculating and returning the SHA-256 hash
    return bytes2hex(sha256(block_data))
end
Out[0]:
calculate_hash

Generation of the first (zero) block — genesis block

Function create_genesis_block creates the first block in the chain — the "genesis block".
It doesn't have a previous hash, so we use an empty string.

In [ ]:
function create_genesis_block()
    index = 0
    timestamp = time() # current time
    data = "Genesis Block"
    previous_hash = "0" # there is no previous block

    hash = calculate_hash(index, timestamp, data, previous_hash)
    return Block(index, timestamp, data, previous_hash, hash)
end
Out[0]:
create_genesis_block

Creating a new block

Function create_next_block creates a new block based on the previous one.
Parameters:

  • previous_block: the previous block in the chain
  • data: data for the new block
In [ ]:
function create_next_block(previous_block, data)
    index = previous_block.index + 1
    timestamp = time()
    previous_hash = previous_block.hash

    hash = calculate_hash(index, timestamp, data, previous_hash)
    return Block(index, timestamp, data, previous_hash, hash)
end
Out[0]:
create_next_block

Chain Integrity Check

Function is_chain_valid checks whether the integrity of the blockchain has been violated.
For this:

  1. Checks whether each hash matches its data.
  2. Checks whether the correct address is specified previous_hash for each block.
In [ ]:
function is_chain_valid(chain::Vector{Block})
    for i in 2:length(chain)
        current_block = chain[i]
        previous_block = chain[i-1]

        # We check whether the block hash matches the recalculated value.
        expected_hash = calculate_hash(
            current_block.index,
            current_block.timestamp,
            current_block.data,
            current_block.previous_hash
        )

        if current_block.hash != expected_hash
            println("Integrity is broken: the hash of the $(current_block.index) block does not match")
            return false
        end

        # Checking whether previous_hash is specified correctly.
        if current_block.previous_hash != previous_block.hash
            println("The sequence is broken: the previous hash of the $(current_block.index) block does not match")
            return false
        end
    end
    return true
end
Out[0]:
is_chain_valid

Block Chain creation and testing

Creating a block chain

In [ ]:
blockchain = Vector{Block}()
Out[0]:
Block[]

Adding the genesis block

In [ ]:
push!(blockchain, create_genesis_block())
Out[0]:
1-element Vector{Block}:
 Block(0, 1.757418165732052e9, "Genesis Block", "0", "89e9605fd77a7c1580679c91026c7c522e4ca2543a54d8b68ae9099769648fe5")

Adding several blocks

In [ ]:
push!(blockchain, create_next_block(blockchain[end], "The first transaction"))
push!(blockchain, create_next_block(blockchain[end], "The second transaction"))
push!(blockchain, create_next_block(blockchain[end], "The third transaction"))
Out[0]:
4-element Vector{Block}:
 Block(0, 1.757418165732052e9, "Genesis Block", "0", "89e9605fd77a7c1580679c91026c7c522e4ca2543a54d8b68ae9099769648fe5")
 Block(1, 1.757418165985186e9, "Первая транзакция", "89e9605fd77a7c1580679c91026c7c522e4ca2543a54d8b68ae9099769648fe5", "5795b75b3f1c46ff0a77c54f91f84bb8702b0d047e81fdc259e2db71c1a87fcd")
 Block(2, 1.757418165985377e9, "Вторая транзакция", "5795b75b3f1c46ff0a77c54f91f84bb8702b0d047e81fdc259e2db71c1a87fcd", "d3113ceee60fdd38051311f312fb1e5579305cbff648fa81f9d2c11f4c7f7b89")
 Block(3, 1.757418165985547e9, "Третья транзакция", "d3113ceee60fdd38051311f312fb1e5579305cbff648fa81f9d2c11f4c7f7b89", "8d4083d1c8c42de81a7d8be592a77e77faa98ab01db0e838f18415d6afa760c0")

Displaying information about the blocks

In [ ]:
println("The block chain:")
for block in blockchain
    println("Index: $(block.index), Data: $(block.data), Hash: $(block.hash), Previous hash: $(block.previous_hash)")
end
Цепочка блоков:
Индекс: 0, Данные: Genesis Block, Хэш: 89e9605fd77a7c1580679c91026c7c522e4ca2543a54d8b68ae9099769648fe5, Предыдущий хэш: 0
Индекс: 1, Данные: Первая транзакция, Хэш: 5795b75b3f1c46ff0a77c54f91f84bb8702b0d047e81fdc259e2db71c1a87fcd, Предыдущий хэш: 89e9605fd77a7c1580679c91026c7c522e4ca2543a54d8b68ae9099769648fe5
Индекс: 2, Данные: Вторая транзакция, Хэш: d3113ceee60fdd38051311f312fb1e5579305cbff648fa81f9d2c11f4c7f7b89, Предыдущий хэш: 5795b75b3f1c46ff0a77c54f91f84bb8702b0d047e81fdc259e2db71c1a87fcd
Индекс: 3, Данные: Третья транзакция, Хэш: 8d4083d1c8c42de81a7d8be592a77e77faa98ab01db0e838f18415d6afa760c0, Предыдущий хэш: d3113ceee60fdd38051311f312fb1e5579305cbff648fa81f9d2c11f4c7f7b89

We check the integrity of the chain

In [ ]:
println("Checking the integrity of the chain: ", is_chain_valid(blockchain) ? "OK" : "Mistake")
Проверка целостности цепочки: OK

Conclusion

In this example, we implemented a simple version of the blockchain in the Julia language.:

  • we have determined the block structure,
  • implemented the generation of SHA-256 hashes,
  • created the genesis block — the beginning of the chain,
  • we learned how to add new blocks,
  • we wrote an integrity check for the entire chain.

This helps to understand the basic principles of blockchain technology: how data is interconnected, why it is protected from changes, and how the system can independently verify its correctness.

Such code can be useful for learning the basics of cryptography, distributed systems, and preparing for more complex projects such as creating cryptocurrencies or smart contracts.