Jami is free software for universal communication that respects the freedom and privacy of its users. At its core, Jami aims to be a complete decentralized, secure, and robust way of communication for the people. This also applies to the Jami Name Service (JNS), a convenient way of finding and connecting to other Jami users using their convenient and easy-to-remember Jami username (rather than their longer Jami ID, which is the hash of their account's public key). This is similar to the Domain Name System (DNS) which is a mapping of human-friendly domain names to harder-to-remember IP addresses. Looking for a solution that would fulfill the above criteria, Jami developers decided to use the blockchain technology—more precisely, the Ethereum network with the future Proof of Stake (PoS) update—as the underlying database for storing the registered usernames and their corresponding account public key.
This article is the first in a series of articles about JNS. In this part, we will examine the evolution of JNS and what lies ahead. First, we will consider the mistakes (which we learned from) of the old JNS implementation and how we managed to recover from them, followed by looking into the big picture of the new architecture of JNS. In the second part, we will dive into the technical details of the next implementation of JNS.
Some time ago, the old JNS was in place using a Proof of Authority (PoA) consensus. This consensus was among many nodes owned by us. Everything was working fine, until some nodes started having Byzantine faults. In distributed systems, a Byzantine fault is any fault that presents different symptoms to different observers. In presence of Byzantine faults, there is possibility of arbitrary failures or unreliabilities in the system, and in a Byzantine fault tolerant system the actors (or nodes, in our case) need to be able reach consensus on a decision in order to prevent the system as a whole from failing. PoA is tolerant to Byzantine faults in up to
N / 2 nodes, where
N is the number of the nodes on the network. After that, consensus could not be reached, and even though Jami users could still register usernames, the registrations were not recorded into the blockchain due to lack of consensus, but only cached on the web server.
The problem was quickly discovered, but things had already happened: many users had registered their username, but were not included in the blockchain. Thus, a migration of the existing registered names on the blockchain to a SQL database was made. The names lost during the crisis were recovered from the web server's logs and inserted in the database. Fortunately, no collisions were found in the logs (no two people had registered the same username)! As of today, the JNS still uses the SQL database as its backing storage.
From this incident, we can conclude that when experimenting with new technology, it would be a good idea to use a technology we are already more familiar with, in parallel to experimenting with the new one, to have more fault tolerance and assurance in case things go haywire.
The road ahead
While moving from Proof of Authority (PoA) to Proof of Stake (PoS), the next implementation of JNS aims to:
- keep the authority to trusted actors;
- have generic storage (e.g. in case of adding new use case); and
- have an updatable logic (e.g. in case of security audit).
The three points are fulfilled respectively by the council, eternal-storage, and proxy-logic smart contracts.
Without diving into too much detail, the council is a contract that owns a list of eternal-storage contracts and a single proxy-logic contract. Members of the council have stakes. The first member of the council is the creator of the contract and owns all the stakes. Members can delegate part of their stakes to non-members (thereby making them members) or to other existing members. Members can issue proposals and vote on them. Only a single proposal can be issued at a time. A proposal passes if it gains more than half of all the stakes existing before its expiration date. If a proposal passes, it will be executed, and new proposals can be issued by members. Examples of proposals that members can issue are the addition of a new eternal-storage contracts and the selection of a new proxy-logic.
The eternal-storage is a simple contract. It has an owner, a logic, and a multitude of mappings from bytes32 to various types. The owner is the creator of the contract (in our case, the council) and is the only one that can change the logic. The logic is typically a contract's address and it is the only address that has write access to all mappings.
The proxy-logic is any contract selected by the council. Typically, this contract will change if security vulnerabilities are found, or if important updates have to be made. When an instance of this contract is selected as the proxy-logic by the council, it is the only one that can have write access to all eternal-storage owned by the council.
To summarize this first part of the series, we saw that the previous implementation of the Jami Name Service was using a Proof of Authority consensus. While functional for some time, it ended up failing due to many Byzantine faults, making consensus unreachable, showing that new technology such as blockchains is not a silver bullet. Fortunately, we managed to recover from it by migrating to a SQL database, which is still the current implementation of JNS, while we plan the next JNS implementation with the aim of migrating back to the blockchain technology, this time using a Proof of Stake consensus, while keeping the authority to trusted actors, having generic storage, and an updatable logic.
In the second part of the series, we will dive into the technical details of the presented smart contracts and more!
Have you ever run into similar issues with consensus in blockchains or know of those who have? We would love to hear about it on our social media.
By Olivier Dion