As we work toward mainnet launch, we should figure out what mechanisms to put in place to mitigate issues caused by buggy smart contract logic. In other words, what happens if already created smart contracts have serious bugs in them?
We could, for example, make Origin smart contracts upgradable. There are various ways to write these. As @DanielVF points out, the greater challenge may be political, since being able to upgrade existing contracts opens up various cans of worms.
Let's discuss!
cc @joshfraser @matthewliu @DanielVF @tyleryasaka @wanderingstan @nick @crazybuster
We should have a way to upgrade our smart contracts and fix any bugs. It's highly unlikely that we're going to get everything perfect on our first try. That said, our goal should be to remove ourselves from having that much power. We should have a function we can call to close that backdoor once we're sufficiently convinced that our code is safe and stable.
It seems to me the political issue may be initially limited.
What really matters now and for at least a year is that it works and no one can expect perfect code from the start.
It will certainly become an issue later on, when real money is involved, but I think you guys have some time before politics kick in.
Just my personal perspective of course.
As I understand the political/ethical point of view, the ideal system on ethereum is a DAO. That's on one extreme, where the other extreme would be centralized oligarchy, like 19th century robber baron with cigar and monocle style centralization.
Historically, movements away from central power have happened: Magna Carta, American Revolution. What differentiates the American system from an oligarchy is the system of checks and balances. Even though there are 100 individuals with the power to create and change how every person living in the country goes about their lives, they can be veto'd and are also elected by the populace. Even though there is an individual which is the head of the armed forces, he/she is also elected and can be impeached. Similarly for the arbitration arm of the government, the supreme court.
Of course, there are criticisms of the system as it currently exists, as the world of 2018 is very different than that of the mid 18th century. But it does seem to me like the mutability/evolutionary capabilities of something like the logic underlying a protocol for decentralized commerce is a governance question. Who can change that logic? Under what circumstances? Whose approval?
As a reference point, IETF RFCs might be an example of the development of interoperability without central authority:
So, I don't think this problem is quite as hard as it seems.
Problem: we want to be able to keep our contracts decentralized, but we want to be able to easily issue updates, as a (mostly) trusted centralized party.
The ideal solution will make it easy for us to roll out updates as long as we have the community's trust. However, part of earning the community's trust will mean that ultimately the community will have a mechanism for opting out of an update that they see as straying from our original mission and promise. If we go rogue at some point in the future, the community should have the option to continue on without us.
The solution is actually pretty straightforward. We have to first separate the data and logic of our contracts. Then we can deal with data and logic upgrades as follows:
The data of course has to be immutable. This works fine until the application requirements change and we want to store the data in a new format. We don't want to have the authority to go back and edit the format of old data or add fields to it or whatever (the way you might perform a migration on a centralized database). Instead, we can simply tag each data contract with a version number. Any formatting or transforming of old data formats will need to happen at the application layer. We can look at a piece of data, know what version it is, and handle it accordingly.
We want our logic to be able to change over time, but we also don't want to leave ourselves a backdoor in solidity (this would not be decentralized). Instead, we should simply release a new logic contract any time we want to perform an upgrade. This logic contract will completely replace the old one.
How do we force people to use the new logic contract? We don't. Again, if we have the community's trust, we can simply guide them to the new logic contract.
Use a proxy contract. Described in this article that @cuongdo also linked to. And here are some example contracts using the proxy method. Origin can centrally own the proxy contract without ever owning the logic contracts. As long as people trust us to release updates, they can use the proxy contract as a guide for which logic contract to use. And because the proxy contract is on the blockchain, solidity code can programmatically reference the most up-to-date contract.
@tyleryasaka I have some questions:
Supporting an unbounded number of versions of the data adds unbounded bloat to the code. We'd need a way to somehow manage that. Maybe we'd have periodic major releases that would allow us to get rid of some backward compatibility code. This could work well with short-lived contracts.
A half-baked idea I was that of "in-memory migrations." They'd be like database migrations (which take the DB from v1 to v2 to ...) and would allow you to, in memory, migrate contract data to the current format so that most of the application code needs to only understand one data format. For example, there'd be a lower-level part of origin.js that performed these "migrations" on smart contract data before passing it on to the rest of origin.js.
Also, there may be useful ideas to borrow from how Stripe does API versioning.
Cardstack has a blog post that describes their upgradable smart contract system. They use a separate storage contract that holds a bunch of mappings and can stay in place indefinitely. Also, they use ENS to point to the latest version of contracts and have a contract upgrade system (as well as a way to freeze the token or specific accounts). This strategy involves less "magic" than other approaches I've seen.
Openzeppelin also has a proxy contract approach, but it has some pitfalls:
delegatecall means that any contracts that inherit from a base upgradable contract class must respect a specific inheritance order to maintain the same storage layoutdelegatecall requires more care than mappings do. This may just be paranoia on my part, but I prefer less magic in delicate parts of the system.Love the idea of using ENS. We already have a few relevant ENS names reserved.
I do not think we should give ourselves the power to freeze specific accounts.
I think we decided to punt on this. Removing my own assignment.
Closing this as we now have multi contract support in GraphQL