-
Notifications
You must be signed in to change notification settings - Fork 430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Upgradeable contracts #1889
Upgradeable contracts #1889
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1889 +/- ##
==========================================
- Coverage 52.97% 52.96% -0.02%
==========================================
Files 215 215
Lines 6782 6782
==========================================
- Hits 3593 3592 -1
- Misses 3189 3190 +1 see 2 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
/// Note that we don't need `set_tail_call(true)` flag | ||
/// because `Mapping` updates the storage instantly on-demand. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we want to elaborate more on that part. Maybe put a link to the documentation that describes what it means to update the state in the RAM vs Storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have such documentation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, but maybe we want to add something like this=)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's on my task-list to add a page on the use.ink
## [Delegator](delegator/) | ||
|
||
Delegator patter is based around a low level cross contract call function `delegate_call`. | ||
It allows a contract to delegate its execution to some on-chain uploaded code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a mistake to present these as two separate ways of upgrading storage - set_code_hash
is almost always used together with delegate_call
to migrate the contract's storage after upgrading its code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While they can be used together, it is also possible to upgrade the storage using only set_code_hash
and delegate_call
. These are the atomic blocks for upgradeability. For more detailed practises on how to upgrade the contract in the best way, there should be a documentation page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delegate_call
doesn't upgrade the contract - i.e. it doesn't change it's logic (one could argue that if all calls delegate then it is but I'd say it's a proxy then) it can only change its data. Hence the only way to upgrade the contract is to:
- forward to a different contract - proxy pattern
- replace the code -
set_code_hash
.
Also, you can only delegate if that logic has been there since the beginning - i.e. since the moment the contract was uploaded. I'd argue that the contract isn't upgraded .
I think the nomenclature is important here b/c if used loosely it will only add to devs confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delegate_call
allows to delegate an execution of logic to another on-chain. If used correctly, you can introduce the upgradeability functionality where delegated code hash can be replaced. The reason why it belongs to upgradeability is because that's how it is implemented in the EVM world - via proxies.
set_code_hash
is the "Polkadot" way of upgradability.
Nonetheless, these nuances should be elaborated in the documentation. The examples just provide a concrete illustration of how these "blocks" can be used individually.
If the delegated code only modifies `Lazy` or `Mapping` field, the keys must be identical and `.set_tail_call(true)` is optional. | ||
This is because `Lazy` and `Mapping` interact with the storage directly instead of loading and flushing storage states. | ||
|
||
If your storage is completely layoutless (it only contains `Lazy` and `Mapping` fields), the order of fields and layout do not need to match for the same reason as mentioned above. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd avoid usage of layoutfull and layoutless since they don't have well-defined meaning. Storage under Lazy
and Mapping
also has a layout, it's just different. Using new terms will only confuse users even more and they're already have a lot to swallow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it is hard to explain in terms of Packed and Non-Packed because storage can be Non-Packed by still layoutful. Here the "layoutfulness" plays an important role.
Addresses #1826
Turns out there are a few hiccups when using
delegate_call
that a develop needs to know. This PR re-introduces the examples and documentation for the upgradeable contracts.