Last month, Facebook announced it had launched the Libra Association alongside several corporate partners such as VISA, Mastercard and Uber. The association’s goal is to launch the Libra Blockchain, which would “serve as a solid foundation for financial services, including a new global currency, which could meet the daily financial needs of billions of people” (source). Here we take a closer look at the technical documentation of Libra to evaluate whether its objectives are realistic, as well as to determine if some of the widespread criticism of the project is warranted.
Overall, we found many reasons to be enthusiastic about Libra, including:
- Libra Core is written in Rust, which is one of the most safe and efficient programming languages. Rust provides comprehensive execution safety and predictable resource usage.
- Libra uses several well-tested blockchain attributes, such as Merkle trees, secure cryptographic libraries and robust consensus protocols.
- Libra has taken upon itself to create a new smart-contract language, Move, which is an ambitious undertaking but also avoids the well-documented issues of other smart contract languages like Solidity.
There is a clear difference in the ideal use cases for Libra and the Exonum™ platform, which is due to the different approaches in defining business-logic. From our review we find that Exonum is better suited for private systems, whereas Libra is designed as a (initially more centralized) public blockchain. Exonum has more customizable options (like cryptographic module replacement), access to time-tested and well-known libraries in Rust, C++ and Java, and more instruments for storing and processing data. For these reasons, it seems Exonum is a better choice for those interested in designing a private application.
Below we get into more detail about these topics and share some comparisons to Exonum’s design structure to help illustrate the similarities and differences between the two blockchain platforms.
Programming Language — Rust
The Exonum team has been building blockchain solutions in Rust since 2016, so it was interesting for us to review Libra Core, which is written entirely in Rust. It consists of 85,000 lines of Rust code split into 607 files within a tidy modules structure. We can say that the source code is well-documented and readable, which will help developers build products for Libra more easily. The installation and usage instructions are clear and concise. It uses the most recent Rust features such as async syntax, but it is apparent that it is primarily focused on utilizing a stable Rust channel — therefore, the code leaves little opportunity for experiments. Libra uses common Rust libraries such as lazy_static, tokio, clap, failure, and has also implemented necessary features, including wrapping the existing code with helpers or using repository forks (in case of the rocksdb library). The Libra team has also implemented their own async actors (instead of using the ones from the actix library).
Processing of Transactions
Any operation involving data on a blockchain is done through a transaction. These transactions are special messages, which contain data and instructions on how to process this data. For example, to add a new user on an Exonum blockchain, we send a transaction called “CreateUser” with the user’s name and his/her public key. After processing this transaction on all the blockchain nodes, our distributed database now contains information about this user. Everyone will be able to review the list of all committed transactions to find when and how this data was added into the blockchain.
Libra transactions also follow this model and work in a similar way to Ethereum transactions. All transactions on Libra are “Protobuf” messages and contain some Move bytecode (we talk about Move later on), arguments for this bytecode program, a public key and an address of the sender. The transactions are also signed with the sender’s private key. To restrict the maximum complexity of transaction business-logic, the Libra Blockchain requires transactions to use gas. Gas is an abstract virtual currency that allows the sender to estimate the “cost” of the bytecode program. Each bytecode operation costs certain amount of gas, and every transaction contains the maximum available gas amount. So, if the program spends all the gas (i.e. by entering the infinite loop), its execution will be stopped. This does mean that anyone can add their own business logic to their transactions, but they will have to use gas for it. For this reason, Libra is efficient for building services for end users. However, the need to pay gas for every transaction can be an issue for large-scale infrastructure projects.
Exonum transactions are Protobuf messages as well, but Exonum transactions contain only parameters and some internal metainformation. All the business-logic is stored in the source code of the blockchain nodes, not inside the transaction. This means Exonum transactions are smaller (in terms of data) but it’s more difficult to update the business-logic.
To prevent a transactions replay attack, Libra uses a simple feature called “Sequence number.” The sequence number is the number of transactions any account sends, and each account keeps its own sequence record. This number is included in every transaction message. The Libra blockchain will not execute the transaction if the Sequence number of the transaction is less than the Sequence number of the sender’s account. In this way, the attacker will be unable to submit the same transaction twice.
Exonum solves the issue of replay attacks by discarding transactions already included into the Exonum blockchain. The framework determines if there are duplicate transactions by the hash of the transaction at the verification step (before broadcasting to other blockchain nodes). To do this, it is necessary to have an additional field in our design to distinguish among transactions with the same set of parameters. We call this field “seed,” and we often use either the current time or a random number as its value.
Another difference is the use of public keys. In Libra, each transaction includes both the public key of the sender as well as his/her address (which is just the hash of the public key). We believe the reason for this is due to the message format they chose. Essentially, they have built a “layer cake” for their transactions, with the payload wrapped in an integrity guarantee — the public key and the cryptographic signature. In Exonum, we use a similar message format, but only the public key is stored in the transaction.
When it comes to transaction design, Exonum and Libra’s concepts look very similar, but there is a fundamental difference in the approaches. On the basis of our review, Exonum’s design is more suitable for private systems where the business logic can be determined only by authorized participants. The typical examples are various state registries, e-voting systems, infrastructure parts of the Internet like ICANN. One of the major advantages of this design is that you don’t need to pay for each transaction. In contrast, Libra is designed as a more centralized public blockchain, with each user writing their own business logic and paying accordingly.
The Libra blockchain stores all its data inside a distributed persistent key-value database built on top of the well-known RocksDB library, called LibraDB. The blockchain is represented as a Merkle tree of transactions. Each “leaf” of such a tree is an executed transaction. Merkle trees enable the blockchain to easily handle hashing and comparing and synchronizing data, but it also offers a powerful feature called cryptographic proofs. Merkle trees allow users to acquire a cryptographic proof for every piece of data inside the blockchain without downloading the whole database. LibraDB is also smart with its storage — it effectively
utilizes disk storage by compressing the tree with different methods. For example, each node has 16 children (instead of two) and long branches are represented with a single node.
Exonum has a similar database structure called MerkleDB, built on top of RocksDB as well. Like Libra, Exonum has cryptographic proofs thanks to its Merkle tree design, but in addition MerkleDB has a more diverse set of data structures and a more complex hierarchical structure of the storage itself. It allows for the developer to choose the right tool for every possible task and effectively solve various programming problems while developing large applications with complicated business-logic.
Both Libra and Exonum use the same cryptographic algorithms and libraries, namely SHA-3 for hashes, elliptic curves Ed25519 for signatures, and all communications between the nodes are encrypted with the Noise Protocol. It is important to note that the current cryptographic module of Libra is subject to change. The new cryptographic module, available in the Libra source code, utilizes traits of Rust for a more flexible API. Exonum’s cryptographic model is secure, but it is more easily replaceable depending on client requirements (which do vary across regions).
In comparison, Libra has more freedom to determine its cryptographic module as it is not dependent on the design needs of clients. The Libra team chose the most standard and well-known algorithms, which seems to indicate they aim for an effective and safe implementation (rather than the “right” one, which again can vary greatly).
Both Libra and Exonum use variations of a well-known practical Byzantine fault tolerant consensus algorithm based on the Tendermint and HotStuff protocols. These algorithms offer strong performance, including the ability to handle thousands of transactions per second; and they are robust and do not require any excessive computational power. However, these algorithms work best with a limited number of blockchain nodes. Libra’s goal is to have 100 nodes processing about 1,000 transactions per second; the baseline goal of an Exonum blockchain is to offer 5,000 transactions per second between four and 16 nodes. This is possible due to Exonum’s light client and use of cryptographic proofs, which means users do not have to run their own node to trust the blockchain.
Internally, the consensus modules of both Exonum and Libra are implemented in an async manner with the tokio library. Libra, as a much younger project, uses the most recent and powerful Rust features including async syntax. It makes the consensus implementation code more readable and maintainable.
Move is a program language developed by the Libra team and is used for smart-contracts on the Libra blockchain. The language is currently noted as a work-in-progress by the Libra Association. The syntax and IR-bytecode are not stabilized yet and may be altered soon. There is no information yet about availability of Move for third party programmers. For now, Move is used for the internal business-logic of the blockchain, including the use of the Libra coin and recording user accounts.
From our review, Move is a simple language and translates to the IR-bytecode almost line-by-line. This bytecode is executed on the Move virtual machine. The virtual machine isolates the smart-contracts and uses the concept of gas (as mentioned above). Move will probably evolve in a more high-level language in the future, as we expect more instruments for developing, debugging and testing of the smart-contracts will be built.
The syntax and semantics of the Move language are definitely inspired by Rust. Like Rust, Move also controls the mutability of references, and uses the same rules for ownership and borrowing as Rust does. Unlike in Rust, however, these rules are controlled on the bytecode level, not at the compiler level. Move also has additional requirements that Rust does not have. For example, all the variables must be declared before usage at the beginning of the function scope.
The current (initial) version of Move supports functions, modules and structures with some pattern-matching abilities.
Internally, Move bytecode is similar to LLVM IR-bytecode, which definitely opens up wide performance optimization opportunities.
A note: We will continue to review the developments of the Libra blockchain and Move programming language and will issue any updates here.