Doing Distributed Systems — The Bitcoin way! (Part 1)

01

Doing Distributed Systems — The Bitcoin way! (Part 1)

Written with ❤️ by:

Bitcoin has taken the world by storm of late. With the Bitcoin price growing by 1600% this year, it’s hard to ignore it — whether you like it or not. But how does it work? Why’s it such a big deal? I’ll try to answer these in this post.

This is a two part post. In this first part, I will talk about the technical challenges involved in making such a system by trying to build such a system on our own. In the second part, I will show how Bitcoin overcomes them.

What is Bitcoin after all?

Bitcoin is a cryptocurrency and worldwide payment system. It is the first decentralized digital currency, as the system works without a central bank or single administrator. (stolen from Wikipedia)

Centralization vs Decentralization

Till now, money as you know has been printed by governments or central banks, and is heavily controlled by them. It is therefore centralized — controlled by a single entity (the government/bank). An example: If today I want to pay you Rs. 1000, I must ask the bank to do it for me. It will first check if I really do have Rs. 1000 in my account, and only then it will update our balances. All transactions like this must be processed and approved by bank. (Ignore cash for now).

Bitcoin on the other hand is Decentralized. There is no single entity that controls the Bitcoin currency. If you are part of the Bitcoin network, you are also more or less equally responsible for Bitcoin to work correctly. This will become clear as you read on.

Centralization has its benefits, like efficiency, but requires us to trust the system. Centralized systems are also more prone to getting attacked than Decentralized systems. And in the matter of money and power, there are people who believe in social merits of decentralization. I’m not interested in discussing those here. I will instead talk about technical hurdles that come in the way of implementing a decentralized system, because that is fun.

Technical stuff begins.

You might ask why we didn’t have a decentralized system before Bitcoin. Because it was so hard, no one knew how to make one. Bitcoin was a pioneer in this respect.

So let’s try conceptually building up such a system on our own, and we’ll see what the big problems could be. To get started, let’s build a simple centralized system (a Bank):

Let’s make a bank

For a bank, you need to have accounts. We can represent accounts in a simple database, with a single table: “Accounts ”. There are two columns for simplicity: Userid and Balance . So whenever user A wants to transfer Rs. 1000 to user B, the bank will reduce user A’s Balance by 1000, and increase B’s by the same. Of course it’ll check if A’s Balance is more than 1000. That’s about it, we have our simple centralized money transfer system.

**Let’s make our decentralized system**

For our discussion, we’ll have 3 users in our network. A with balance 1000, B with 500 and C with 200. Let’s not get into how they got these balances, not interesting for now.

Now to make a decentralized system, we must realize that we can’t have one server. In the case of a bank, we trusted banks to keep the records correctly in its database. In a decentralized system, we don’t want users to trust a single entity. So there is no single database where we update records. Instead, we need each user to maintain his own records!

In order for things to work correctly, each user will need to be aware of all the transactions in the network (Don’t worry about privacy for now). This is crucial. I’ll show why.

Problem of double spending

Let’s say A wants to transfer 300 to C in this system. Then C must know that A actually does have 300 to pay him. If C knows A’s balance, i.e. 1000, then he can just update his local database copy, and set A’s balance to 700. If you think a bit, you’ll realize that everyone needs to know everyone else’s balance if they need to receive money from the other. Why? Because otherwise we’ll have cheaters in the system.

Consider that A has paid 300 to C. So A’s real balance is 700 now. If B was not aware of this transaction, then A can “fool” B by sending him 1000, since B still thinks that A’s balance is 1000. He’ll think he owns 1500 now! Of course that’s not true, but his local database will have values (0,1500,200).

This is called “double spending” — spending the same money again! Here A spent Rs. 300 again. Of course that’s a bad thing and it must be avoided. And we can do that by making each user aware of all the users’ balances. In essence, **we need all nodes in the network to maintain the same state** (the state represents each user’s balance). So they each maintain the same table at all times.

How to maintain the same state?

Now if A sends 300 to C, all users need to update their copies to the new values correctly — they all must be in sync. In order to do so, they need to communicate with each other. And the only way two systems can communicate in a network is by sending messages to each other. So something like this should happen:

Do you notice any problems here?

Byzantine behavior

One problem is that there’s no guarantee that A sent the same message to both B and C, he could have lied, or there could’ve been some communication error. This is an important problem, especially if you’re making a system around money — you shouldn’t trust all users to behave nicely. Btw, this is called a Byzantine faulty distributed system — where nodes can misbehave.

Issue of timing

The second problem is a little more subtle. You must realize that sending messages, however fast it be, takes a finite amount of time. And if you have a large enough network, with nodes spread all around the world, latencies can vary from a few milliseconds to several hundreds of milliseconds. We must also consider that intermediate routers, or nodes themselves can be down at times. So having said that network delays are important to consider, let me get straight to the problem. We’ll assume the same initial balances (1000, 500, 200). Let’s say there are two transactions (Take a pen in hand!):

Let’s also assume all nodes are honest for now. According to our protocol:

What happens if B gets C’s message before A’s message? B will reject that message and that transaction needs to be retried. This worsens if A’s message can’t reach B due to some network error for a long time.

Wait, what just happened? A and C saw the messages in the same order. B saw it in a different order! This is a big problem in distributed systems.

A small digression: what is time? For most purposes it can be thought of as a sequence of events, we can call them ‘ticks’ — each event can be considered as a clock’s tick. If we can say that event X happened after event Y for any two events X and Y, then we have a strong ordering of events. This ordering is often enough to characterize ‘time’ in a system. However as we saw, and in distributed systems in general, different nodes can see different sequences, therefore see different ‘time’. Distributed systems can’t have a global notion of time as we know it . People have defined other versions of time, but that’s another matter. See Lamport clocks¹.

The issue of different ordering is often solved in distributed systems using something called a Leader election algorithm . The idea is basically this — if you can’t have multiple nodes see the same order of messages, you pick a leader amongst the nodes, and let the leader decide the order of messages. The other nodes will trust the leader’s decision. To give each one a fair chance, you can have the elections at regular intervals. And things work out nicely.

Except, they don’t. At least, not in all cases. If you were careful, you’d have noticed a problem with the above — “other nodes will trust the leader’s decision”. In our case, we can’t trust the nodes! In fact, it has been proven in 1982 that the problem of reaching agreement among Byzantine nodes in an asynchronous system (our case) has no solution, without any randomization².

This is where Bitcoin comes in. As far as I know, it is the first system that solves this problem in a general distributed system — it solves all the issues I mentioned above: double spending and consensus in a byzantine distributed system. And that’s a big deal.

In the next post, I’ll talk about mining, proof of work, and blockchains, and explain how Bitcoin uses these to solve the problems I talked about.

[1] There’s a special subclass of distributed systems called synchronous systems, where you can define time as we know it. But we won’t assume our system to be synchronous distributed system.

[2] https://groups.csail.mit.edu/tds/papers/Lynch/jacm85.pdf

Written by Parth Thakkar