Research Summary: Dissimilar Redundancy in DeFi

(Joint work with @danhper)

TL;DR

  • The meteoric rise of decentralized finance (DeFi) has been accompanied by a plethora of frequent and often financially devastating attacks on its protocols. There have been over 70 exploits of DeFi protocols, with the total of lost funds amounting to approximately $1.5 billion USD.
  • In this paper, we introduce the notion of “dissimilar redundancy” for smart contracts. The core idea is that a program logic is implemented more than once, ideally using different programming languages. For each implementation, the results of the execution should match before the state of the blockchain is allowed to change.
  • This research is inspired by and has clear parallels to the field of avionics, where on account of the safety-critical environment, flight control systems typically feature multiple redundant implementations. We argue that the high financial stakes in DeFi protocols merit a conceptually similar approach, and we provide a novel algorithm for implementing dissimilar redundancy for smart contracts.

Citation

Perez, Daniel, and Lewis Gudgeon. “Dissimilar Redundancy in DeFi.” arXiv preprint arXiv:2201.12563 (2022). [2201.12563] Dissimilar Redundancy in DeFi

Core Research Question

Can smart-contract risk (i.e., the risk of an exploit or bug) be meaningfully reduced through the use of multiple redundant implementations of the same program?

Background

  • Smart contracts: Smart contracts are program objects that live on blockchains. The crucial property of smart contracts that we rely on in this work is atomicity - namely that a transaction either succeeds or fails in its entirety - as this ensures that the blockchain cannot be left in an invalid or inconsistent state
  • Scaling solutions: Given the high cost of undertaking transactions on Ethereum, many scaling solutions have emerged that try to solve this issue.
  • Smart contract vulnerabilities: There have been many different forms of smart contract exploits over the years, often leading to significant losses of money. In this paper, we focus purely on the technical security of smart contracts, and specifically logical bugs, which alone have resulted in millions of dollars of losses to DeFi protocols.

Summary

  • DeFi protocol hacks are frequent - with more than 70 to date totalling losses of more than $1.5 billion. For a financial infrastructure that is purportedly going to replace traditional finance, this is worrisome.
  • The severity of the issue of hacks is exacerbated by the non-custodial nature of DeFi systems. Unlike traditional financial systems, where in the event of financial disaster there are often safety-nets such as the state or insurers, in DeFi there are no such safety provisions at scale.
  • Moreover, while there is a nascent insurance market for DeFi insurance, such solutions provide only a (necessary) second-best solution: providing coverage in the event of a DeFi system failure. A first-best solution is to prevent the failure in the first place.
  • In aviation, the safety-critical nature has led to the emergence of a practice of implementing multiple separate and redundant flight control systems.
  • For example, the Boeing 777 features a Fly-By-Wire flight control system that had to meet extremely high levels of functional integrity and reliability.
  • To do this, it has three separate primary flight computers, with each computer containing three dissimilar internal computational lanes.
  • The lanes differ in terms of compilers, power supply units and microprocessors, with, for example, lane 1 using the AMD 29050, lane 2 the Motorola 68040 and lane 3 the Intel 80486. Within each of the three flight computers, two of the lanes acted as monitors while the third lane was in command.
  • In this way, the flight computer features a form of redundancy that is dissimilar, with the multiple lanes being resistant to bugs induced by microprocessors or compilers.
  • We apply the core of this idea to smart contracts. We implement and detail a system based on a proxy pattern which relies on dissimilar implementations of a DeFi protocol, and cross-checks one against the other before effecting any on-chain state change.
  • On Ethereum, this approach has already been taken for client implementations, with the community maintaining multiple open-source clients, developed by different teams and using different programming languages.
  • The purpose of this approach is to strengthen the network and make it more diverse, with a view to avoiding a single client dominating the network in order to remove single points of failure. We extend this concept to the smart contract layer itself.

Method

  • This paper presents a protocol that enables the approach of dissimilar redundancy to be used in the context of Ethereum, and the Ethereum Virtual Machine.
  • On Ethereum today a standard programming pattern is the proxy architecture pattern. With a proxy pattern, all message calls to a contract first go through a proxy contract. With this pattern, the former contract contains the actual implementation logic while the latter contract provides a storage layer. At present, a common use of this pattern is to provide contract upgradeability. Although contracts cannot be directly upgraded once deployed, using this pattern allows upgradeability to be mimicked. Simply, the proxy contract can be instructed to use a different logic contract, while retaining the same storage.
  • In our work, we expand on this pattern by allowing the proxy contract to delegate to multiple underlying contracts at once. This is in contrast to the standard pattern which only permits delegation to a single implementation at a time. Our core idea is to enable a proxy contract to sequentially call two different implementations - supposedly identical in logic and ensure that the data returned by function calls to each implementation as well as return values from an arbitrary number of checks provided by the contract developer match.
  • Although the overall idea is straightforward, the actual implementation requires several technical difficulties to be overcome.
  • The figure below outlines the proxy pattern we develop.

Results

  • We evaluated our approach with reference to a smart contract that implements a simple auction system. We implemented the auction contract with identical behaviour in both Solidity and Vyper, but purposefully introduced two implementation bugs in the Vyper implementation of the contract logic.
  • We tested our approach both locally and in a real-world deployment.
  • In a local environment, we use Python in combination with Brownie and the Hypothesis testing library to generate test cases. The details of the testing are in the paper, but with this approach, locally we find that with only a few lines of code it was possible to have extensive coverage of a tested function that was able to automatically find discrepancies between two implementations.
  • In a real world environment, we deployed to Polygon. An important strength of our approach is that it is possible to use two implementations not only during development and during testing, but also after the contract is deployed, ensuring that all the transactions executed will be consistent between the different implementations provided. Now considering gas costs, we provide the estimated USD cost of our approach in Table 2 below.
Start First bid Subsequent bid Finalize
Proxied 0.0229 0.0092 0.0060
Solidity 0.0094 0.0045 0.0029
Vyper 0.0108 0.0045 0.0029

Discussion and Key Takeaways

  • Developing the approach above necessitated overcoming a number of technical challenges
    • The first such challenge is that of how program implementations could be called with the same state. Our approach requires both implementations to be called with the same initial state. However, typically sequential program calls would modify the state. We describe our solution in detail in the paper, but in a nutshell we overcome this by having the proxy delegate first to itself, passing in call data as an argument, along with the implementation and call checks to perform.
    • The second challenges centers on how the checks that we want to be performed after each program execution should be encoded. A check is a call to a contract that needs to be consistent after each execution.
    • The full code of the proxy contract can be found on GitHub. In particular, the solution to our first problem is around line 168 and the encoding used is described from line 29.
  • Our approach comes with strong benefits in relation to smart contract reliability, but has some limitations.
    • Transaction fees: This approach will always at least double the cost of transactions, and potentially increase it further if many calls need to be performed. There is no direct way to prevent this or improve it significantly at the implementation level. This means that the viability of this approach will depend on the willingness of users to support different levels of transaction fees.
    • Development cost: The approach implies greater development costs, as the same program intent needs to be implemented more than once. However, in the same way that the Ethereum Foundation funds external teams to maintain different clients, a well established protocol could potentially do the same.
    • Storage layout: Our approach requires implementations to use the same storage layout, since the proxy contract will be storing all the states of the contract. This imposes some potentially undesirable rigidity on alternative code implementations.

Applicability

  • This work is applicable to anyone developing smart contracts who is seeking to reduce bug risk and improve quality assurance.
  • In particular, we believe that this approach is particularly well suited for protocols that have well-defined specs.
  • It allows multiple teams to independently work on the implementation of the spec and ensuring that the resulting implementations are indeed equivalent.
20 Likes

Welcome to the forum @fskforte – it’s always a real treat having original authors in the forum

Do you know of other models used for mission-critical systems used in other industries?

1 Like

Welcome to the forum @fskforte and thank you for the excellent summary!

The proposed proxy architecture is really interesting. I’m curious about how it would handle execution mismatches if, for example, the execution outcome of the Solidity implementation leads to a different state transition relative to its Vyper counterpart. A lot of popular proxy and admin implementations, like Open Zeppelin’s, have pause() functions that can effectively halt the application.

Would that be the desired outcome in the event of a mismatch?

7 Likes

Oh wow, this is so cool! Thank you fsxforte for this research.

I have a question about its potential applications in the future. I can’t determine that if this idea is “nonsense”, “doable but not realistic”, or “could be a direction that’s worth working on”.

Currently there’s a lot of contract code (templates) being reused, like the ones from openzepplin - and it’s a good thing because it makes the foundation of contract security safer by reusing battle-tested code.

Under the dissimilar redundancy paradigm, we want to introudce redundancy to the ecosystem, and we believe that it can be a good security practice for everyone.

Do you think that it is possible to (say, on some extermely cheap L2), design an incentive pattern for people to code and deploy modularized contract parts for different but minimalistic function on the network?
Ideally, by competition(between different implementation contracts of the same minimalistic logic) and regulated calling (spec-wise) of redundant contracts, can we make this a standard practice that is both cheaper than auditing (CANNOT REPLACE AUDIT COMPLETELY, it’s complementary), and as a result the whole ecosystem is safer?

Sorry if I worded my imaginary situation wrong or I got your research result wrong - it’s quite fascinating!

6 Likes

Following up on (or adding to) @jmcgirk’s and @cipherix’s questions:

I enjoyed the detail you provided on the Boeing 777 Fly-By-Wire system, specifically the three different “lanes” using various power supplies and processors. In that example, the “redundancy” seems very reliably implemented in the physical world. If there is any discrepancy in the lanes, that would be known virtually instantly given the speed of semiconductors, and the plane (presumably) could not take off.

Everyone agrees on the need for secure smart contract implementation, and your avionics analogy sounds promising. But unless I’m misunderstanding, it’s more an analogy at this point than reproduction of a literal model. For one thing, smart contracts occur in a complex, decentralized network which adds enormous complications that we don’t see in the physical airplane model. You also mention that transaction fees would “at least” double, and this is in systems already beset by great gas costs and scalability issues.

Could you walk us a bit more through the similarities to the avionics “three lane” analogy and how they would or wouldn’t apply to networked smart contracts?

8 Likes

Hey @jmcgirk - thanks for the welcome!

There are quite a few areas/industries where other models are used for mission-critical systems. Rail is one (e.g. https://web-archive.southampton.ac.uk/deploy-eprints.ecs.soton.ac.uk/8/1/fm_sc_rs_v2.pdf) (quite an impressive track record for bugs in the abstract!).

The label ‘N-version’ programming can also be used here, with applications also extending to electronic voting.

1 Like

Thanks @cipherix!

The idea would be that if there is a mismatch, the execution is halted. Due to atomicity of Ethereum transactions, we can be sure that such a halting would not result in some inconsistent state, so the transaction could revert. The counterpart to this idea is that a transaction only executes if all program versions agree with the return value/state change

1 Like

Hey @Jerry_Ho!

This is an interesting idea. It sounds like you are effectively suggesting a market for modularized contract parts, where different developers / teams of developers would be in a tacit competition to produce reliable code, in the same way vendors are in tacit competition to produce reliable widgets. It’s a cool idea.

I agree that competition and regulation (in terms of defining interfaces, etc) would be important. Thinking through the economic design would also be important. For the developer of a modularized smart contract component, could there be some sort of reward mechanism for creating the most robust implementation of a specific component?

3 Likes

Hey @rlombreglia, thanks for this reply!

I think this is more than just an analogy. While it is true that smart contracts live in a complex decentralized world, the EVM itself does exist as a single entity comprised of every node in the network. (I’m limiting things to the Ethereum world here). Since transactions are atomic, it is possible to enforce that multiple implementations have to agree in order for the transaction to be fully executed. This is what we do in the paper, essentially. While of course the networking does add complexity, I think of this as complexity at the network layer/layer zero rather than the blockchain layer / layer one!

4 Likes

Heyo @fsxforte, it is great to find you here! Hope I will be seeing you during SBC’22 in person with @danhper.

I think this is such an amazing design, however, the gas + development overhead might have extremely exclusionary effects. One reason for this is that, in my memory, most protocols that were hacked are early projects with large demand. Since they are early projects, most teams are swamped with other tasks. Therefore, for these projects, implementing this design will not just be a technical decision but also a strategic/cultural one (will Gryostable implement this design?). It will slow down their Go-To-Market (GTM) due to technical overhead and user acquisition due to high gas costs.

So, after publishing this paper, what have you learned from chatting with early-stage founders and what are their reception on this? Also, I am curious what the late-stage protocols (Uni, Maker, Comp, Aave) think about this design. Do you see any of them experimenting with this any time in the near future (12 months)?

Thank you so much for coming by! Amazing work.

6 Likes

Welcome to the forum @Kydo and thank you for joining this fun discussion! You bring up a good point on this architecture’s impact on users.

As @fsxforte discussed in section V of the paper, transaction fees in fact make this design prohibitive in networks that face congestion and high fees.

From the paper:

As we have seen in the previous section, this approach will always at least double the cost of transactions and potentially increase it further if many calls need to be performed. There is not any direct way to prevent this issue or improve it significantly at the implementation level. This means that using such an approach on a expensive network, such as Ethereum, is almost unfeasible, as the price increase for transactions would likely be unacceptable for many users. However, more and more layer two solutions are being developed, with transaction fees orders of magnitude lower than what can be seen on Ethereum mainnet. This is for example the case of Polygon mainnet, which we used for the evaluation earlier. As we can see in Table II, although the costs have been doubled, this represents an increase in the order of a cent in the worst case. As Ethereum is moving towards a layer 2 future [17] and transaction fees become negligible, the fee overhead of our approach might become less and less of a concern.

Indeed, the doubling of transaction fees in Ethereum as it stands does impose an adoption barrier. But perhaps this architecture could be solely applied to critical functions within the application, like a custody contract, where redundancy and stronger guarantees around state transitions are key.

I’d also be interested in hearing what the feedback from the community has been. Given the prevalence of DeFi exploits, could founders leverage this architecture to build versions of their applications suitable for power users?

In other words, is there a scenario where an application has a “version” that implements dissimilar redundancy for power users willing to pay a premium in fees for increased security?

6 Likes

Hey Kydo! Yes, should see you in person at SBC!

Agreed that the gas and development might have exclusionary effects given typical current development approaches to smart contracts. I think there’s a debate to be had about whether it should have these effects in an ideal approach to development, and what the ideal GTM speed should really be.

Regarding chatting with early-stage founders, this paper is only just out and we’re just starting to talk with people now about this approach. Very interested indeed to hear what people make of it at both a technical and philosophical level. And perhaps we can continue this discussion at SBC!

Thank you, and thanks for the comments!

4 Likes

Sorry for the long wait ser. I totally agree with this and I think this is quite an interesting design. @fsxforte what do you think?

1 Like

Thanks for the clarification (and sorry for my late response). Yes, I think I missed the point (when reading your summary) that the atomicity of transactions made this possible at the blockchain layer.

3 Likes

@fsxforte always glad to see more novel ways of protecting the space from hacks, losses and exploits.

The procedure seems solid with potential real-world applicability.

However, I have one reservation…

You mentioned in the takeaways that the process will always at least double the cost of transactions, potentially increasing it further if many calls are made.

This point reminds me of the never-ending trade-off blockchain users make between security, scalability, and performance.

In the end, it is still a solution worth its troubles :thinking:

3 Likes

@fsxforte Your article is insightful and well-written, but there are a few things we should be conscious of.

No, and again, no. The purpose of smart contracts is to do away with the need for redundant systems. All smart contracts are subject to increased risk if one of them fails to spring, activate, or perform as intended. When it comes to statistics and odds, if you practice what you preach, you’ll increase your cost, work energy, and effort, which will also increase your risk.

Each contract must be tailored to the specifics of the transaction. Since when do businesses permit programmers to write contracts instead of lawyers, who typically do this work?

When did lawyers start learning how to create smart contracts?

A “smart contract” is nothing more than the fantasy of a crypto enthusiast, even though it seems plausible.

1 Like

Summary (comments 1-16):

Dissimilar Redundancy is designed to strengthen smart contracts and protect protocols in decentralized finance systems against attacks and vulnerabilities. While this research summary covers how this approach would be used in Ethereum and the Ethereum Virtual Machine, the discussion further explores how other industries use and benefit from this kind of safety mechanism and regulatory needs that may arise in Ethereum.

Here is a breakdown of questions, topics, and key responses (KR) in the discussion:

  1. Are there other models used in other industries that use of mission-critical systems? (posed by jmcgirk)

KR: rlombreglia questions how the model of redundancy in avionics transfers to smart contract ecosystems that may have higher complexity and more costs associated with the model.

KR: fsxforte points to the rail industry and digital-based voting

KR: fsxorte also addresses rlombreglia’s concern of implementation feasibility by explaining how transactions would have to occur to ensure proper execution.

  1. Can gas prices could hinder development and adoption of this approach? (posed by Kydo)

KR: Cipherix shares how double transactions could be applied to certain functions in the application

KR: Jerry_Ho questions if redundancy can be offered as a premium feature as opposed to being a standard.

Points of Disagreement
The question of whether the model of redundancy that exists in avionics is truly transferable to networked smart contracts was highlighted early on. While decentralized systems are complex, multiple implementations of an algorithm on the network layer may be necessary for safe transactions. Additionally, high transaction fees could be an adoption and scalability issue but it is unsure whether it’s a small price given the possible increase in security.

Unresolved questions
Are these redundancy algorithms scalable and worthwhile considering this approach doubles cost of transactions?

Links to similar Posts:

  1. DeFiRangers: Detecting Price Manipulation Attacks on DeFi Applications
  2. Attacking the DeFi Ecosystem with Flash Loans for Fun and Profit
  3. DeFiRANGERS: Detecting Price Manipulation Attacks On DeFi Applications
2 Likes

Thanks for the summary @ttaloute21!

For anyone who is interested, I also just published a blog post that somewhat extends this idea. Welcome any thoughts on that!

Hey @Humphery! Thank you for your engagement with the work. I do however completely disagree with what you’re saying. The purpose of smart contracts is to, inter alia, allow non custodial and global programs. To that end, redundancy would seem to help their purpose

1 Like