-
Notifications
You must be signed in to change notification settings - Fork 429
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
German
authored
Aug 28, 2023
1 parent
3d57446
commit 9b39318
Showing
13 changed files
with
383 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,8 @@ decodable | |
decrement | ||
defrag | ||
defragmentation | ||
delegatee | ||
delegator | ||
deploy | ||
dereferencing | ||
deserialize/S | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Upgradeable Contracts | ||
|
||
There are different ways a contract can be upgraded in ink! | ||
|
||
This folder illustrates some of the common and best practices to achieve upgradeability in your contracts. | ||
|
||
## [`set-code-hash`](set-code-hash/) | ||
|
||
ink! provides an ability to replace the code under the given contract's address. | ||
This is exactly what `set_code_hash()` function does. | ||
|
||
However, developers needs to be mindful of storage compatibility. | ||
You can read more about storage compatibility on [use.ink](https://use.ink/basics/upgradeable-contracts#replacing-contract-code-with-set_code_hash) | ||
|
||
## [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. | ||
|
||
It is different from a traditional cross-contract call | ||
because the call is delegate to the **code**, not the contract. | ||
|
||
Similarly, the storage compatibility issue is also applicable here. | ||
However, there are certain nuances associated with using `delegate_call`. | ||
|
||
First of all, as demonstrated in the example, if the delegated code intends to mutate the caller's storage, | ||
a developer needs to be mindful. If the delegated code modifies layout-full storage | ||
(i.e. it contains at least non-`Lazy`, non-`Mapping` field), the `.set_tail_call(true)` flag of `CallFlags` needs to be specified and the storage layouts must match. | ||
This is due to the way ink! execution call stack is operated | ||
(see [Stack Exchange Answer](https://substrate.stackexchange.com/a/3352/3098) for more explanation). | ||
|
||
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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Ignore build artifacts from the local tests sub-crate. | ||
/target/ | ||
|
||
# Ignore backup files creates by cargo fmt. | ||
**/*.rs.bk | ||
|
||
# Remove Cargo.lock when creating an executable, leave it for libraries | ||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock | ||
Cargo.lock |
29 changes: 29 additions & 0 deletions
29
integration-tests/upgradeable-contracts/delegator/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
[package] | ||
name = "delegator" | ||
version = "4.2.0" | ||
authors = ["Parity Technologies <admin@parity.io>"] | ||
edition = "2021" | ||
publish = false | ||
|
||
[dependencies] | ||
ink = { path = "../../../crates/ink", default-features = false } | ||
delegatee = { path = "delegatee", default-features = false, features = ["ink-as-dependency"] } | ||
|
||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } | ||
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } | ||
|
||
[dev-dependencies] | ||
ink_e2e = { path = "../../../crates/e2e" } | ||
|
||
[lib] | ||
path = "lib.rs" | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"ink/std", | ||
"scale/std", | ||
"scale-info/std", | ||
] | ||
ink-as-dependency = [] | ||
e2e-tests = [] |
9 changes: 9 additions & 0 deletions
9
integration-tests/upgradeable-contracts/delegator/delegatee/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Ignore build artifacts from the local tests sub-crate. | ||
/target/ | ||
|
||
# Ignore backup files creates by cargo fmt. | ||
**/*.rs.bk | ||
|
||
# Remove Cargo.lock when creating an executable, leave it for libraries | ||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock | ||
Cargo.lock |
25 changes: 25 additions & 0 deletions
25
integration-tests/upgradeable-contracts/delegator/delegatee/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "delegatee" | ||
version = "4.2.0" | ||
authors = ["Parity Technologies <admin@parity.io>"] | ||
edition = "2021" | ||
publish = false | ||
|
||
[dependencies] | ||
ink = { path = "../../../../crates/ink", default-features = false } | ||
|
||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } | ||
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } | ||
|
||
[lib] | ||
path = "lib.rs" | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"ink/std", | ||
"scale/std", | ||
"scale-info/std", | ||
] | ||
ink-as-dependency = [] | ||
e2e-tests = [] |
41 changes: 41 additions & 0 deletions
41
integration-tests/upgradeable-contracts/delegator/delegatee/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#![cfg_attr(not(feature = "std"), no_std, no_main)] | ||
|
||
#[ink::contract] | ||
pub mod delegatee { | ||
use ink::storage::{Mapping, traits::ManualKey}; | ||
#[ink(storage)] | ||
pub struct Delegatee { | ||
addresses: Mapping<AccountId, i32, ManualKey<0x23>>, | ||
counter: i32, | ||
// Uncommenting below line will break storage compatibility. | ||
// flag: bool, | ||
} | ||
|
||
impl Delegatee { | ||
/// When using the delegate call. You only upload the code of the delegatee contract. | ||
/// However, the code and storage do not get initialized. | ||
/// | ||
/// Because of this. The constructor actually never gets called. | ||
#[allow(clippy::new_without_default)] | ||
#[ink(constructor)] | ||
pub fn new() -> Self { | ||
unreachable!( | ||
"Constructors are not called when upgrading using `set_code_hash`." | ||
) | ||
} | ||
|
||
/// Increments the current value. | ||
#[ink(message)] | ||
pub fn inc(&mut self) { | ||
self.counter += 2; | ||
} | ||
|
||
|
||
/// Adds current value of counter to the `addresses` | ||
#[ink(message)] | ||
pub fn append_address_value(&mut self) { | ||
let caller = self.env().caller(); | ||
self.addresses.insert(caller, &self.counter); | ||
} | ||
} | ||
} |
Oops, something went wrong.