Side Effects due to Speculative Execution in Hyperledger Fabric
Since my last post on deploying System Chaincodes in Hyperledger Fabric, I have experimented more with Chaincodes and gotten further along with my Master’s thesis. In this post I will detail our experience dealing with privacy hazards due to side effects from speculative execution in Fabric.
What is Speculative Execution in Fabric ?
Most blockchains(Ethereum, Tendermint, Quorum etc.) achieve a consistent view of transactions by adopting some sort of state machine replication among peers. In this approach a transaction is ordered first and then executed. This requires the transaction to be executable deterministically and be run on all the peers, this leads to performance and scaling bottlenecks.
On the contrary, Fabric’s architecture follows the “Execute first and then order” paradigm. What this means is that a transaction is executed speculatively and then it is checked for correctness(i.e conflicts in the ledger state by the endorsers). This allows for ordering to be done by a subset of the nodes increasing the overall throughput.
This model improves the throughput of the system but it opens avenues for side effects due to speculative execution of a transaction, Especially if the developer is not mindful of this quirk of Fabric while developing. I will highlight below the common mistakes a developer could do and go through some potential applications where this could be exploited and give my view about how we can overcome this issue. We were unable to find any documentation which warns the user of this, however I can confirm that it was acknowledged in one of the paper from IBM Research.
Side Effects from Speculative execution:
Side effects arise when the transaction performs an irreversible operation but the transaction is dropped i.e not considered by the ordering service. A scenario where a transaction could be dropped is when there are two writes on the same key at around the same time(before one of them is committed) but only one of them is considered by the ordering service due to a Write-Write conflict.
Consider the above code sample which defines function readAorB which consumes a read token and allows reading of either a or b but not both. In an event where there are two requests to the function, and they execute before either of them can be committed both the transactions view the read token as unused and go into the respective blocks and return the data.
Demonstration of a side effect :
To make things interesting we present the above example as a chaincode and some scripts to deploy and test a small toy use case to observe the side effects due to speculative reads.
Some interesting scenarios where these side effects can be exploited:
The example above is just a toy example where we read A or B, but we can have many examples in the same style.
- Free reads in Pay for access: a client may purchase a “token” to read one record from the database, e.g. to download an ebook. Speculative reads would let a client effectively double spend that token.
- Escape audit logs: Access logging is a pragmatic approach to privacy by allow clients easy access to a large data source but audit every time a client reads data, this enforces accountability on the reader of the data as they can be tracked if they read the data without authorization. This sort of speculative execution can be exploited by malicious clients to read data without being logged.
- Zero knowledge proofs, oblivious transfer, or related cryptography gadgets: Zero knowledge proof and other similar class of protocols in cryptography there is an established pattern where the “proof verifier” is only allowed to choose only one value to read. In such a scenario speculative reads can be used to read more than required amount of data.
- Reconstruction of secrets: This is an application we are working on at the Decentralized Systems Lab. We want to store secrets in the peers by storing them as shares and have the ability to reconstruct them. Here, one side effect of execution would be reconstruction of secret data. Let’s say a transaction gets dropped after reconstructing the data, there is no way to reverse this as the data would have already been revealed.
To conclude, it is obvious from above that we have to remove side effects in our transaction. One way to achieve this is to have every read or write happen as a separate transaction. Looking at our readAorB example from earlier a solution for Speculative reading would be to have the updating of the read token and the actual reading in two separate transactions. In other words having reads and writes separately.
It would be beneficial for developers of chaincode if the official documentation has information about this and certain guidelines on how to avoid issues about the same.
About me :
I am not a developer of hyperledger fabric and my knowledge and views are limited to my use case and project.