Blockchain networks need a way for distributed computers, called nodes, to agree on the state of the system. This process is called consensus.
Different blockchain architectures use different consensus mechanisms. Four important concepts are:
Proof of Work (PoW)
Proof of Stake (PoS)
Proof of Authority (PoA)
Byzantine Fault Tolerance (BFT)
This article explains how they work using simplified algorithms and Python examples.
Proof of Work
The idea
Proof of Work requires participants, usually called miners, to perform computational work.
The goal is to find a value called a nonce such that the hash of the block satisfies a specific condition.
For example, suppose we require the SHA-256 hash to start with four zeros:
0000a82f...
Because cryptographic hashes are unpredictable, miners must try many different nonce values.
Basic algorithm
function mine(block, difficulty):
nonce = 0
while true:
block.nonce = nonce
hash = SHA256(block)
if hash starts with "0" repeated difficulty times:
return block
nonce = nonce + 1
The important property is that finding a valid nonce can require a lot of computation, while verifying it is relatively easy.
Python example
import hashlib
def calculate_hash(data, nonce):
message = f"{data}{nonce}"
return hashlib.sha256(message.encode( )).hexdigest()
def mine(data, difficulty):
nonce = 0
target = "0" * difficulty
while True:
block_hash = calculate_hash(data, nonce)
if block_hash.startswith(target):
return nonce, block_hash
nonce += 1
nonce, block_hash = mine("Alice pays Bob 10 coins", 4)
print("Nonce:", nonce)
print("Hash:", block_hash)
A possible result could look like:
Nonce: 45231
Hash: 0000c7a1f3...
The exact nonce will be different each time.
Why is this useful?
PoW makes it expensive to rewrite blockchain history because an attacker would need to perform a large amount of computational work.
The main disadvantage is energy consumption.
Bitcoin is the best-known example of a blockchain using Proof of Work.
Proof of Stake
The idea
Proof of Stake replaces computational competition with economic commitment.
Instead of asking:
"Who can perform the most computation?"
the network asks:
"Which validator should create the next block?"
Validators lock cryptocurrency into the protocol. This is called staking.
A simplified validator-selection algorithm could look like this:
function select_validator(validators):
total_stake = sum(validator.stake)
random_value = random(0, total_stake)
cumulative = 0
for validator in validators:
cumulative += validator.stake
if random_value <= cumulative:
return validator
A validator with more stake has a greater probability of being selected.
Python example
import random
validators = {
"Alice": 100,
"Bob": 50,
"Charlie": 25
}
def select_validator(validators):
total_stake = sum(validators.values())
choice = random.uniform(0, total_stake)
cumulative = 0
for validator, stake in validators.items():
cumulative += stake
if choice <= cumulative:
return validator
validator = select_validator(validators)
print("Selected validator:", validator)
Here the total stake is:
100 + 50 + 25 = 175
Therefore, approximately:
Alice → 100 / 175 = 57.1%
Bob → 50 / 175 = 28.6%
Charlie → 25 / 175 = 14.3%
This is only a simplified illustration. Real PoS protocols use considerably more sophisticated validator-selection and consensus algorithms.
Slashing
Proof-of-Stake systems can penalize validators that violate protocol rules.
For example:
def slash(validator, stake, penalty):
return max(0, stake - penalty)
alice_stake = 100
alice_stake = slash(
"Alice",
alice_stake,
20
)
print(alice_stake)
Output:
80
The idea is that validators have an economic reason to follow the protocol.
Ethereum uses Proof of Stake.
Proof of Authority
The idea
Proof of Authority uses a predefined group of trusted validators.
Instead of mining or staking, validators are authorized to participate based on their identity and reputation.
Imagine a network with:
Validator A
Validator B
Validator C
Validator D
Only these validators are allowed to create or validate blocks.
Simplified algorithm
authorized_validators = {
Alice,
Bob,
Charlie,
David
}
function validate_block(block, validator):
if validator not in authorized_validators:
reject
if verify_signature(block, validator):
accept
else:
reject
Python example
authorized_validators = {
"Alice",
"Bob",
"Charlie"
}
def validate_block(block, validator):
if validator not in authorized_validators:
return False
return block["validator"] == validator
block = {
"data": "Alice pays Bob",
"validator": "Alice"
}
print(validate_block(block, "Alice"))
print(validate_block(block, "Eve"))
Output:
True
False
Eve cannot validate the block because she is not an authorized validator.
Advantages
PoA can provide:
high transaction throughput
low energy consumption
predictable validation
low computational requirements
Disadvantage
The main trade-off is that the network depends on a relatively small group of known authorities.
This makes PoA particularly suitable for some private, enterprise, or consortium blockchains, where participants are known.
Byzantine Fault Tolerance
The problem
BFT addresses a different problem.
Imagine several nodes need to agree on:
"Should transaction X be accepted?"
Some nodes may be:
offline
malfunctioning
sending conflicting messages
malicious
These problematic nodes are called Byzantine nodes.
The challenge is to allow honest nodes to reach agreement despite these failures.
Practical Byzantine Fault Tolerance
One famous approach is Practical Byzantine Fault Tolerance (PBFT).
A simplified PBFT protocol has three main phases:
Client Request
|
v
PRE-PREPARE
|
v
PREPARE
|
v
COMMIT
|
v
Execute Request
The nodes communicate with each other during these phases.
A simplified algorithm is:
1. Client sends a request to the primary node.
2. Primary broadcasts PRE-PREPARE.
3. Replicas verify the proposal.
4. Replicas broadcast PREPARE.
5. Nodes collect enough matching PREPARE messages.
6. Nodes broadcast COMMIT.
7. After enough COMMIT messages,
the transaction is considered committed.
For a classic PBFT system with n nodes, the protocol can tolerate:
f = floor((n - 1) / 3)
Byzantine nodes.
Therefore:
n = 4 → f = 1
n = 7 → f = 2
n = 10 → f = 3
This means a system with 7 replicas can tolerate up to 2 Byzantine replicas under the classic PBFT assumptions.
Simplified BFT Example
Consider four nodes:
Node A
Node B
Node C
Node D
Suppose Node D is malicious.
The honest nodes receive:
A → ACCEPT
B → ACCEPT
C → ACCEPT
D → REJECT
The network can still reach:
CONSENSUS = ACCEPT
because the honest nodes have enough agreement.
A very simplified implementation could be:
def reach_consensus(votes):
accept = votes.count("ACCEPT")
reject = votes.count("REJECT")
return "ACCEPT" if accept > reject else "REJECT"
votes = [
"ACCEPT",
"ACCEPT",
"ACCEPT",
"REJECT"
]
result = reach_consensus(votes)
print("Consensus:", result)
Output:
Consensus: ACCEPT
This code is not a real BFT implementation. It only illustrates the basic idea of reaching agreement despite a conflicting node.
Real BFT protocols need authentication, message ordering, view changes, quorum rules, replay protection, and mechanisms for handling malicious communication.
Comparing the Algorithms
| Mechanism | Main idea | Resource | Typical participants |
|---|---|---|---|
| PoW | Computational work | CPU/GPU/ASIC power | Miners |
| PoS | Economic stake | Cryptocurrency | Validators |
| PoA | Authorized identity | Identity/reputation | Approved validators |
| BFT | Agreement despite failures | Communication/quorums | Distributed nodes |
The important distinction is that BFT is primarily a family of fault-tolerant consensus techniques, while PoW, PoS, and PoA describe different ways of determining who can participate in block production or validation.
A Simple Blockchain Architecture
A simplified blockchain can be represented as:
Transaction
|
v
+------------+
| Validation |
+------------+
|
v
+----------------+
| Consensus |
| PoW / PoS / |
| PoA / BFT |
+----------------+
|
v
+------------+
| New Block |
+------------+
|
v
+------------+
| Blockchain |
+------------+
For example, with Proof of Work:
Transactions
|
v
Create Block
|
v
Mining / PoW
|
v
Valid Hash?
/ \
No Yes
| |
Retry Broadcast
|
v
Other Nodes
|
v
Add to Chain
With Proof of Stake:
Transactions
|
v
Create Block
|
v
Select Validator
|
v
Validate Block
|
v
Consensus
|
v
Add to Chain
The four concepts solve related but different problems:
Proof of Work uses computational effort to make block production expensive.
Proof of Stake uses economic incentives and locked cryptocurrency to select and control validators.
Proof of Authority uses a known and authorized group of validators.
Byzantine Fault Tolerance focuses on allowing distributed nodes to reach agreement even when some nodes fail or behave maliciously.
In a real blockchain, these concepts can also be combined. For example, a protocol can use a validator-selection mechanism together with a BFT-style consensus algorithm.
The Python examples above are intentionally simplified: they demonstrate the core algorithms and intuition, not production-ready blockchain implementations.