Introducing Immutable State — Part 1

Guillaume Bonnot
Caasiope Labs
Published in
4 min readNov 20, 2018

This article will review the problems of the current architecture raised in the first Caasiope Improvement Proposal (CIP) : Immutable State

The Caasiope blockchain architecture is based on Command and Query Responsibility Segregation (CQRS), where a single thread is in charge of processing the transactions and updating the ledger.

Introducing CQRS

The main workflow separates commands from queries. Commands are handled sequentially in a dedicated thread and are working on an exclusive representation of the state of the ledger. When the ledger is updated, the cache is immediately updated and the changes are asynchronously pushed to the database. Queries are handled in parallel and are reading from the cache or the database.

The current implementation is using a data structure that works well in the context of maintaining a single state that will be updated at every action. The current implementation would perform well in the case of a trading engine, where every order need to check the last state of the orderbook and could modify it. In this case, most commands needs an exclusive access to the same resource.

The 3 states of the ledger

The problem is, the current data structure is not suited to maintaining 3 different states in parallel : the current state of the ledger, the current post state of the validator, the post state proposed by the consensus.

The current state of the ledger is only rarely updated, once every block, and is mostly used for read only operations.

The current post state of the validator is really frequently updated and is currently a wrapper on top of the current state, that only contains the changes made by the transactions included in the post state.

The post state proposed by the consensus needs to be quickly computed and validated before sending the result to the other validators. This post state is also implemented as a wrapper, meaning that even it will be destroyed when a new block will be included, even if their are the same.

Tracking account declarations

In order to validate the signatures of a transaction, it is required to have access to the list of the currently declared accounts. For example in the case of a multi-signature account, the signature engine will try to get the declaration of the multi-signature and use it to determine if the number of signature required is reached.

The current implementation considers that if the signature engine can find the multi-signature declaration in the list, it means it had already been declared.

The result of the current model is that if you want to validate a transaction from a multi-signature account in your local wallet, you need to create a wrapper of the current state, that also contains the declarations on your local wallet.

Transactions kept in memory

The cache is keeping in memory everything that was loaded from the database with a data structure equivalent to the underlying SQL schema. In order to speed up fetching transactions input outputs by account, we are currently using an index.

The state of ledger kept in memory is currently keeping all transactions ever included in a block in memory.

On the other hand, determining if a transaction has already been included is made trivial, has we have the full list of the transactions included in memory.

The current solution requires keeping 2 times the same data in different forms to satisfy different needs from commands and queries. This solution has too much overhead and cannot scale, an alternative architecture needs to be implemented, while still providing the same features.

Adapting CQRS

The best practice when using CQRS is to use two separate data models, one optimized for queries, while the other one also contains the business logic. Most of the times, it will drastically reduce the complexity of the project by totally eliminating concurrency issues.

However, because the business logic of Caasiope already needs to concurrently handle 3 different states of the ledger, we can question the choice to have a separate query data model.

In the current architecture, we decided to separate everything and the result was that we also duplicated everything, both the information and the processing.

Exploiting the fact that blockchains are immutable by design, we could create a data model which represent its state using immutable parts. Such an architecture would allow the blockchain state to be explored and extended by multiple concurrent threads…

To be continued…

In the second part, we will take a look at the changes proposed by CIP #1 : Immutable State and how they solve the problems exposed in this article.

Looking for an opensource blockchain community ? Join us on www.caasiope.net

--

--

Guillaume Bonnot
Caasiope Labs

Software & Blockchain Architect, CEO @ Helios Services