Create your own blockchain using Python (pt. 8)

Incentives and Transaction fees

Guillaume Belanger
9 min readOct 31, 2021

In the last section, we introduced Proof-of-Work which involves nodes having to solve difficult problems in order for new blocks to be created. Now let me ask you a question: why on earth would you spend your CPU power to help secure the blockchain network? Unless you received something in exchange, you probably wouldn’t do it. And that’s the point of this section.

In Satoshi Nakamoto’s white paper on bitcoin, a whole section is reserved for incentive. Why did he care about this concept and what did he mean by it? Satoshi’s goal was to build a decentralized network that enables peer-to-peer transactions of value. If this network is decentralized, the various entities that own nodes need incentive to keep their node working. Else why would they do it?

Incentive is why most people got into cryptocurrencies. If we go back a couple of years ago before you knew everything about blockchains, you probably heard at some point that some strange people were getting paid for “mining” crypto or that companies built data centers full of GPU servers (or ASIC’s) solely focused on mining (or resolving the Proof-of-Work puzzle). The explanation is simple, block creators receive rewards for creating blocks. For miners the calculus is simple: If the reward is higher than the operational costs of running the node, mining makes sense.

Coinbase

Block creators are incentivized to be part of the blockchain network by receiving rewards for each block mined. Rewards are a combination of two things:

  • Transaction fees
  • Block rewards

Those two rewards are added up and given to the node owner by inserting a new transaction in the block’s list of transactions. This transaction is called the coinbase transaction (not to confused with the company Coinbase) and is typically the first transaction of the list.

Transaction fees

Up to now, we always worked under the assumption that for each transaction the output amount had to match the input. Reality is a bit different: outputs amount to slightly less than inputs and the difference is the transaction fee.

Let’s use an example. Alice has an unspent transaction output (UTXO) of 5 and she wants to send 3 to Bob. Here’s a possibility of how her transaction outputs could look like:

  • 3 to Bob
  • 1.8 to Alice
Outputs amount to slightly less than inputs

The node that will create the block will keep the difference between the inputs and the outputs: 5-(3+1.8) = 0.2. Here the transaction fee is 0.2.

I can read in your mind and you are asking yourself: what decides the amount transaction fees? Are those set arbitrarily? Are they decided by the blockchain protocol? The answer is pretty simple. Transaction fees are decided by the transaction creator based on market value. Here’s how to think about it. When a node creates a new block, it will try to maximize its gains by including transactions that give it the highest rewards. If not many transactions are made, nodes will include most/all of them which should drive fees down. On the other hand, if lots of transactions are made, competition between people that want their transaction to be written on the blockchain will drive fees to increase. But if fees are too high, the number of transactions will decrease and nodes will accept lower transaction fees. Just to repeat myself, transaction fees are decided by the transaction creator based on the market value.

Monetary policy

Currently, most of the world’s developed nations use fiat money which means that the value of money is decided by monetary policy. Those policies are decided by the countries’ central banks whose economists will typically try to optimize two key performance indicators: Inflation and economic activity.

In Canada for example, eight time a year, the Bank of Canada adjusts the policy interest rate. In a slow economy, the bank targets low rates in order to encourage spending while in a heated economy, they target high rates to encourage moderation. More importantly related to our subject of interest, Bank of Canada controls the money supply through a tool called quantitative easing (QE). Here’s Investopedia’s definition of QE:

To execute quantitative easing, central banks increase the supply of money by buying government bonds and other securities. Increasing the supply of money lowers interest rates. When interest rates are lower, banks can lend with easier terms. Quantitive easing is typically implemented when interest rates are already near zero, because, at this point, central banks have fewer tools to influence economic growth.

It is important to know that other monetary systems either exist or have existed in the past and the gold standard is probably the most known of them all. Under the gold standard, the country’s money has a gold equivalent value. Simply put, this means that you could exchange your 20$ bill for a fixed amount of gold that doesn’t change over time. In such a system, the monetary policy is very much left on automatic pilot since the amount of gold in circulation depends on extraction, not on policies decided by central banks’ economists. Canada, United States, Great Britain and a lot of other countries used this standard for a while. As of today, most of developed nations are on the fiat standard and use tools such as interest rate policies and quantitative easing to try to control inflation and economic activity.

Why are we talking about monetary policy here? Cryptocurrencies just like regular currencies have monetary policies. For most cryptocurrencies, the total number of “money” in the network is not a static value: the supply changes over time based on a monetary policy decided by the developers. Each cryptocurrency has a different policy on how it creates (or burns) money. This idea is very similar to what central banks are doing with their currencies. The main difference is that for cryptocurrencies, monetary policies are embedded in code while central banks have humans changing those policies over time based on the current economic landscape. Note that having policies be embedded into code doesn’t mean that they can’t evolve over time. For example, Ethereum recently changed its monetary policy through what they call an EIP (Ethereum Improvement Proposals). Here’s an excerpt from EIP-1559 where the authors discuss potential impacts of the modifications they are proposing.

By burning the base fee, we can no longer guarantee a fixed Ether supply. This could result in economic instability as the long term supply of ETH will no longer be constant over time. While a valid concern, it is difficult to quantify how much of an impact this will have. If more is burned on base fee than is generated in mining rewards then ETH will be deflationary and if more is generated in mining rewards than is burned then ETH will be inflationary. Since we cannot control user demand for block space, we cannot assert at the moment whether ETH will end up inflationary or deflationary, so this change causes the core developers to lose some control over Ether’s long term quantity.

For bitcoin specifically, the way new money is added to the system is trough block rewards. Block creators receives “new money” when creating new blocks. The block reward decreases over time until the total supply reaches 21 Million bitcoin. Specifically, the reward reduces by half every 210 000 blocks. When Bitcoin started, miners received 50 bitcoins for creating a new block. Today, they receive 6.25 bitcoins. In opposition to most fiat currencies, bitcoin has a fixed supply: there will never be more than 21 Million bitcoins. However, just like Ethereum, Bitcoin is code and code can change. At any point in time, developers could propose a change to this policy and if the majority of nodes agree to it, the policy will change. That being said, I see this as somewhat unlikely to happen since its fixed supply is an important part of Bitcoin’s identity, for better or for worse.

I am far from an expert in monetary policy and I am not able to differenciate a good monetary policy from a bad one before actually watching the societal outcome. One of the most important consequences of the advent of cryptocurrencies is that they got more people interested in the various options available to us and got them trying to figure out which ones are better than others and which ones can lead to a flourishing society. I find this aspect particularly fascinating.

Transaction format

Now, back to coding. As mentioned earlier, the first transaction in a new block pays the miner for his work. Now since the block reward is “newly printed money”, there is no UTXO to refer to.

{
'inputs': [],
'outputs': [
{
"amount": 6.45,
"locking_script": "OP_DUP OP_HASH160 <miner public key hash> OP_EQUAL_VERIFY OP_CHECKSIG"
}
]
}

Here we will have an empty list for inputs and the outputs will contain the same 2 fields as before (amount and locking script). The amount is the sum of the block reward (6.25) and transaction fees (0.2) and the locking script associates the amount to the miner public key hash.

New block creation

We need to improve our ProofOfWork class to include this new coinbase transaction. To do so, we build a new get_coinbase_transaction method that simply returns a new transaction based on transaction fees.

# src/node/new_block_creation/new_block_creation.pyclass ProofOfWork:
def __init__(self):
self.blockchain = get_blockchain_from_memory()
self.new_block = None

@staticmethod
def get_coinbase_transaction(transaction_fees: float) -> dict:
owner = Owner(private_key=miner_private_key)
transaction_output = TransactionOutput(
amount=transaction_fees + BLOCK_REWARD,
public_key_hash=owner.public_key_hash
)
return {"inputs": [],
"outputs": [transaction_output.to_dict()]}

We also implement a get_transaction_fees that goes trough each stored transactions, sums all transaction fees and return the total:

# src/node/new_block_creation/new_block_creation.pyclass ProofOfWork:
def __init__(self):
self.blockchain = get_blockchain_from_memory()
self.new_block = None

def get_transaction_fees(self, transactions: list) -> int:
transaction_fees = 0
for transaction in transactions:
input_amount = 0
output_amount = 0
for transaction_input in transaction["inputs"]:
utxo = self.blockchain.get_transaction_from_utxo(transaction_input["transaction_hash"])
if utxo:
utxo_amount = utxo["outputs"][transaction_input["output_index"]]["amount"]
input_amount = input_amount + utxo_amount
for transaction_output in transaction["outputs"]:
output_amount = output_amount + transaction_output["amount"]
transaction_fees = transaction_fees + (input_amount-output_amount)
return transaction_fees

Finally, we modify our create_new_block metod so that it calls those 2 new methods and includes the coinbase transaction at the end of the block.

# src/node/new_block_creation/new_block_creation.pyclass ProofOfWork:
def __init__(self):
self.blockchain = get_blockchain_from_memory()
self.new_block = None

def create_new_block(self):
transactions = get_transactions_from_memory()
if transactions:
transaction_fees = self.get_transaction_fees(transactions)
coinbase_transaction = self.get_coinbase_transaction(transaction_fees)
transactions.append(coinbase_transaction)
block_header = BlockHeader(
merkle_root=get_merkle_root(transactions),
previous_block_hash=self.blockchain.block_header.hash,
timestamp=datetime.timestamp(datetime.now()),
noonce=0
)
block_header.noonce = self.get_noonce(block_header)
block_header.hash = block_header.get_hash()
self.new_block = Block(transactions=transactions, block_header=block_header)
else:
raise BlockException("", "No transaction in mem_pool")

A truly distributed blockchain

Up to now, he have built a blockchain that enables secure transaction of value between people. We incentivize people to take part in the system by rewarding them trough transaction fees and new money. Let’s take a step back and look at the root of all information, Wikipedia. Reading the blockchain definition:

Blockchains are typically managed by a peer-to-peer network for use as a publicly distributed ledger

While the blockchain we created is frankly awesome, it is also centralized. It runs on my laptop and nobody else except me can add blocks to it. Here we learned how to incentivize people to take part in it but we didn’t build the infrastructure for new nodes to be added. In a future article, we’ll deep dive into truly distributing our code.

Code repository

Create your own blockchain using Python

References

--

--

Guillaume Belanger

Guillaume is a software developer from Montreal who writes about bip bop stuff.