From da4fcb40b4fe1cc17a8f0851460afe28e7fbbf5b Mon Sep 17 00:00:00 2001 From: will <64425242+willser@users.noreply.github.com> Date: Fri, 25 Mar 2022 22:32:55 +0800 Subject: [PATCH 1/4] Add a function `ink_env::set_code_hash` --- crates/env/src/api.rs | 29 ++++++++++++++++++++++++ crates/env/src/backend.rs | 10 ++++++++ crates/env/src/engine/off_chain/impls.rs | 4 ++++ crates/env/src/engine/on_chain/ext.rs | 7 ++++++ crates/env/src/engine/on_chain/impls.rs | 4 ++++ 5 files changed, 54 insertions(+) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index fb96c44e87c..25bc1a2e251 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -534,3 +534,32 @@ where TypedEnvBackend::caller_is_origin::(instance) }) } + +/// Replace the contract code at the specified address with new code. +/// +/// # Note +/// +/// There are a couple of important considerations which must be taken into account when +/// using this API: +/// +/// 1. The storage at the code address will remain untouched. This means that contract developers +/// must ensure that the storage layout of the new code is compatible with that of the old code. +/// +/// 2. Contracts using this API can't be assumed as having deterministic addresses. Said another way, +/// when using this API you lose the guarantee that an address always identifies a specific code hash. +/// +/// 3. If a contract calls into itself after changing its code the new call would use +/// the new code. However, if the original caller panics after returning from the sub call it +/// would revert the changes made by `seal_set_code_hash` and the next caller would use +/// the old code. +/// +/// # Parameters +/// +/// - code_hash:New code hash. +/// +/// # Errors +/// +/// `ReturnCode::CodeNotFound` +pub fn set_code_hash(code_hash: &[u8; 32]) -> Result<()> { + ::on_instance(|instance| instance.set_code_hash(code_hash)) +} diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index cb7b7723a9e..8f9680b7156 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -282,6 +282,16 @@ pub trait EnvBackend { E: From, F: FnOnce(u32) -> ::core::result::Result<(), ErrorCode>, D: FnOnce(&[u8]) -> ::core::result::Result; + + /// Replace the contract code at the specified address with new code. + /// + /// # Parameters + /// + /// - code_hash:New code hash. + /// # Errors + /// + /// - If code not found. + fn set_code_hash(&mut self, code_hash: &[u8]) -> Result<()>; } /// Environmental contract functionality. diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 7c302b16d21..0e80751aea0 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -318,6 +318,10 @@ impl EnvBackend for EnvInstance { let decoded = decode_to_result(&out[..])?; Ok(decoded) } + + fn set_code_hash(&mut self, _code_hash: &[u8]) -> Result<()> { + unimplemented!("off-chain environment does not support contract invocation") + } } impl TypedEnvBackend for EnvInstance { diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index f35cae20da2..6f2995ae366 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -347,6 +347,8 @@ mod sys { message_hash_ptr: Ptr32<[u8]>, output_ptr: Ptr32Mut<[u8]>, ) -> ReturnCode; + + pub fn seal_set_code_hash(code_hash_ptr: Ptr32<[u8]>) -> ReturnCode; } } @@ -676,3 +678,8 @@ pub fn caller_is_origin() -> bool { let ret_val = unsafe { sys::seal_caller_is_origin() }; ret_val.into_bool() } + +pub fn set_code_hash(code_hash: &[u8]) -> Result { + let ret_val = unsafe { sys::seal_set_code_hash(Ptr32::from_slice(code_hash)) }; + ret_val.into() +} diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index da6a54bba82..0f2580eb568 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -312,6 +312,10 @@ impl EnvBackend for EnvInstance { let decoded = decode_to_result(&output[..])?; Ok(decoded) } + + fn set_code_hash(&mut self, code_hash_ptr: &[u8]) -> Result<()> { + ext::set_code_hash(code_hash_ptr).map_err(Into::into) + } } impl TypedEnvBackend for EnvInstance { From 06239078a9a0b307d7044204a3b91cf7049641a1 Mon Sep 17 00:00:00 2001 From: will <64425242+willser@users.noreply.github.com> Date: Sun, 27 Mar 2022 20:39:17 +0800 Subject: [PATCH 2/4] Add an example of `ink_env::set_code_hash`. --- examples/upgradeable-contracts/README.md | 5 ++ .../set-code-hash/Cargo.toml | 38 +++++++++++++++ .../set-code-hash/lib.rs | 45 ++++++++++++++++++ .../set-code-hash/new-increamenter/Cargo.toml | 35 ++++++++++++++ .../set-code-hash/new-increamenter/lib.rs | 46 +++++++++++++++++++ 5 files changed, 169 insertions(+) create mode 100644 examples/upgradeable-contracts/set-code-hash/Cargo.toml create mode 100644 examples/upgradeable-contracts/set-code-hash/lib.rs create mode 100644 examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml create mode 100644 examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs diff --git a/examples/upgradeable-contracts/README.md b/examples/upgradeable-contracts/README.md index e15846ed618..c51d1854781 100644 --- a/examples/upgradeable-contracts/README.md +++ b/examples/upgradeable-contracts/README.md @@ -19,3 +19,8 @@ more information on proxy patterns. * Executes any call that does not match a selector of itself with the code of another contract. * The other contract does not need to be deployed on-chain. * State is stored in the storage of the originally called contract. + + +## [`set-code`](/~https://github.com/paritytech/ink/tree/master/examples/upgradeable-contracts/set-code-hash) + +* Update contract code by `set_code_hash`. diff --git a/examples/upgradeable-contracts/set-code-hash/Cargo.toml b/examples/upgradeable-contracts/set-code-hash/Cargo.toml new file mode 100644 index 00000000000..f5afcc3c188 --- /dev/null +++ b/examples/upgradeable-contracts/set-code-hash/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "incrementer" +version = "1.0.0" +edition = "2021" +authors = ["Will"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ink_primitives = { version = "3.0.0", path = "../../../crates/primitives", default-features = false } +ink_prelude = { version = "3.0.0", path = "../../../crates/prelude", default-features = false } +ink_metadata = { version = "3.0.0", path = "../../../crates/metadata", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "3.0.0", path = "../../../crates/env", default-features = false } +ink_storage = { version = "3.0.0", path = "../../../crates/storage", default-features = false } +ink_lang = { version = "3.0.0", path = "../../../crates/lang", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +[lib] +name = "incrementer" +path = "lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["std"] +std = [ + "ink_primitives/std", + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_lang/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] + + diff --git a/examples/upgradeable-contracts/set-code-hash/lib.rs b/examples/upgradeable-contracts/set-code-hash/lib.rs new file mode 100644 index 00000000000..11f8874c485 --- /dev/null +++ b/examples/upgradeable-contracts/set-code-hash/lib.rs @@ -0,0 +1,45 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use ink_lang as ink; + +#[ink::contract] +pub mod incrementer { + + #[ink(storage)] + pub struct Incrementer { + count: u32, + } + + impl Incrementer { + /// Creates a new counter smart contract initialized with the given base value. + #[ink(constructor)] + pub fn new(init_value: u32) -> Self { + Self { count: init_value } + } + + /// Creates a new counter smart contract initialized to `0`. + #[ink(constructor)] + pub fn default() -> Self { + Self::new(0) + } + + /// Splice `base` and `target` together. + #[ink(message)] + pub fn inc(&mut self) { + self.count += 1; + ink_env::debug_println!("count is {},use old code", self.count); + } + + #[ink(message)] + pub fn get(&self) -> u32 { + self.count + } + + /// Set new code to this contract. + #[ink(message)] + pub fn set_code(&mut self, code_hash: [u8; 32]) { + ink_env::set_code_hash(&code_hash).expect("Fail to set code."); + ink_env::debug_println!("set code_hash success"); + } + } +} diff --git a/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml b/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml new file mode 100644 index 00000000000..051f1587b2b --- /dev/null +++ b/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "new-incrementer" +version = "0.1.0" +edition = "2021" +authors = ["Will"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ink_primitives = { version = "3.0.0", path = "../../../../crates/primitives", default-features = false } +ink_metadata = { version = "3.0.0", path = "../../../../crates/metadata", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "3.0.0", path = "../../../../crates/env", default-features = false, features = ["ink-debug"] } +ink_storage = { version = "3.0.0", path = "../../../../crates/storage", default-features = false } +ink_lang = { version = "3.0.0", path = "../../../../crates/lang", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +[lib] +name = "new_incrementer" +path = "lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["std"] +std = [ + "ink_primitives/std", + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_lang/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] diff --git a/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs b/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs new file mode 100644 index 00000000000..ec5ca9a7b47 --- /dev/null +++ b/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs @@ -0,0 +1,46 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use ink_lang as ink; + +#[ink::contract] +pub mod incrementer { + + #[ink(storage)] + pub struct Incrementer { + count: u32, + } + + impl Incrementer { + /// Creates a new counter smart contract initialized with the given base value. + #[ink(constructor)] + pub fn new(init_value: u32) -> Self { + Self { count: init_value } + } + + /// Creates a new counter smart contract initialized to `0`. + #[ink(constructor)] + pub fn default() -> Self { + Self::new(0) + } + + /// Splice `base` and `target` together. + #[ink(message)] + pub fn inc(&mut self) { + // Different step size with old contract. + self.count += 4; + ink_env::debug_println!("count is {},use new code", self.count); + } + + #[ink(message)] + pub fn get(&self) -> u32 { + self.count + } + + /// Set new code to this contract. + #[ink(message)] + pub fn set_code(&mut self, code_hash: [u8; 32]) { + ink_env::set_code_hash(&code_hash).expect("Fail to set code."); + ink_env::debug_println!("set code_hash success"); + } + } +} From b3bf653dcdfb64e7cb61edfc2f94625c6cc5e120 Mon Sep 17 00:00:00 2001 From: will <64425242+willser@users.noreply.github.com> Date: Mon, 28 Mar 2022 20:50:57 +0800 Subject: [PATCH 3/4] Fix spelling mistake --- crates/env/src/api.rs | 4 ---- crates/env/src/backend.rs | 3 --- 2 files changed, 7 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 25bc1a2e251..51497577f4a 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -553,10 +553,6 @@ where /// would revert the changes made by `seal_set_code_hash` and the next caller would use /// the old code. /// -/// # Parameters -/// -/// - code_hash:New code hash. -/// /// # Errors /// /// `ReturnCode::CodeNotFound` diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 8f9680b7156..e80bd9e3dcb 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -285,9 +285,6 @@ pub trait EnvBackend { /// Replace the contract code at the specified address with new code. /// - /// # Parameters - /// - /// - code_hash:New code hash. /// # Errors /// /// - If code not found. From 25268c64208f82c8b7b01bcbe1019d51c98ceb81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Fri, 22 Apr 2022 10:27:19 +0200 Subject: [PATCH 4/4] Apply suggestions from code review --- crates/env/src/api.rs | 4 +-- crates/env/src/backend.rs | 6 ++-- crates/env/src/engine/off_chain/impls.rs | 2 +- examples/upgradeable-contracts/README.md | 2 +- .../set-code-hash/Cargo.toml | 17 ++++++----- .../set-code-hash/lib.rs | 22 ++++++++++---- .../set-code-hash/new-increamenter/Cargo.toml | 19 ++++++------ .../set-code-hash/new-increamenter/lib.rs | 30 +++++++++++++++---- 8 files changed, 68 insertions(+), 34 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 51497577f4a..049fe97e9eb 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -542,7 +542,7 @@ where /// There are a couple of important considerations which must be taken into account when /// using this API: /// -/// 1. The storage at the code address will remain untouched. This means that contract developers +/// 1. The storage at the code hash will remain untouched. This means that contract developers /// must ensure that the storage layout of the new code is compatible with that of the old code. /// /// 2. Contracts using this API can't be assumed as having deterministic addresses. Said another way, @@ -555,7 +555,7 @@ where /// /// # Errors /// -/// `ReturnCode::CodeNotFound` +/// `ReturnCode::CodeNotFound` in case the supplied `code_hash` cannot be found on-chain. pub fn set_code_hash(code_hash: &[u8; 32]) -> Result<()> { ::on_instance(|instance| instance.set_code_hash(code_hash)) } diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index e80bd9e3dcb..028b5748cf4 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -283,11 +283,13 @@ pub trait EnvBackend { F: FnOnce(u32) -> ::core::result::Result<(), ErrorCode>, D: FnOnce(&[u8]) -> ::core::result::Result; - /// Replace the contract code at the specified address with new code. + /// Sets a new code hash for the current contract. + /// + /// This effectively replaces the code which is executed for this contract address. /// /// # Errors /// - /// - If code not found. + /// - If the supplied `code_hash` cannot be found on-chain. fn set_code_hash(&mut self, code_hash: &[u8]) -> Result<()>; } diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 0e80751aea0..d4a491ccbeb 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -320,7 +320,7 @@ impl EnvBackend for EnvInstance { } fn set_code_hash(&mut self, _code_hash: &[u8]) -> Result<()> { - unimplemented!("off-chain environment does not support contract invocation") + unimplemented!("off-chain environment does not support `set_code_hash`") } } diff --git a/examples/upgradeable-contracts/README.md b/examples/upgradeable-contracts/README.md index c51d1854781..fd4773f3b68 100644 --- a/examples/upgradeable-contracts/README.md +++ b/examples/upgradeable-contracts/README.md @@ -21,6 +21,6 @@ more information on proxy patterns. * State is stored in the storage of the originally called contract. -## [`set-code`](/~https://github.com/paritytech/ink/tree/master/examples/upgradeable-contracts/set-code-hash) +## [`set-code-hash`](/~https://github.com/paritytech/ink/tree/master/examples/upgradeable-contracts/set-code-hash) * Update contract code by `set_code_hash`. diff --git a/examples/upgradeable-contracts/set-code-hash/Cargo.toml b/examples/upgradeable-contracts/set-code-hash/Cargo.toml index f5afcc3c188..9e8c38fb6ed 100644 --- a/examples/upgradeable-contracts/set-code-hash/Cargo.toml +++ b/examples/upgradeable-contracts/set-code-hash/Cargo.toml @@ -1,18 +1,19 @@ [package] name = "incrementer" -version = "1.0.0" +version = "3.0.1" edition = "2021" -authors = ["Will"] +authors = ["Parity Technologies "] +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ink_primitives = { version = "3.0.0", path = "../../../crates/primitives", default-features = false } -ink_prelude = { version = "3.0.0", path = "../../../crates/prelude", default-features = false } -ink_metadata = { version = "3.0.0", path = "../../../crates/metadata", default-features = false, features = ["derive"], optional = true } -ink_env = { version = "3.0.0", path = "../../../crates/env", default-features = false } -ink_storage = { version = "3.0.0", path = "../../../crates/storage", default-features = false } -ink_lang = { version = "3.0.0", path = "../../../crates/lang", default-features = false } +ink_primitives = { version = "3.0.1", path = "../../../crates/primitives", default-features = false } +ink_prelude = { version = "3.0.1", path = "../../../crates/prelude", default-features = false } +ink_metadata = { version = "3.0.1", path = "../../../crates/metadata", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "3.0.1", path = "../../../crates/env", default-features = false } +ink_storage = { version = "3.0.1", path = "../../../crates/storage", default-features = false } +ink_lang = { version = "3.0.1", path = "../../../crates/lang", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } diff --git a/examples/upgradeable-contracts/set-code-hash/lib.rs b/examples/upgradeable-contracts/set-code-hash/lib.rs index 11f8874c485..a5c5d1e97cd 100644 --- a/examples/upgradeable-contracts/set-code-hash/lib.rs +++ b/examples/upgradeable-contracts/set-code-hash/lib.rs @@ -5,6 +5,8 @@ use ink_lang as ink; #[ink::contract] pub mod incrementer { + /// This struct contains the smart contract storage. + /// The storage will always be retained, even when `set_code_hash` is called. #[ink(storage)] pub struct Incrementer { count: u32, @@ -23,23 +25,33 @@ pub mod incrementer { Self::new(0) } - /// Splice `base` and `target` together. + /// Increments the counter value which is stored in the contract's storage. #[ink(message)] pub fn inc(&mut self) { self.count += 1; - ink_env::debug_println!("count is {},use old code", self.count); + ink_env::debug_println!("The new count is {}, it was modified using the original contract code.", self.count); } + /// Returns the counter value which is stored in this contract's storage. #[ink(message)] pub fn get(&self) -> u32 { self.count } - /// Set new code to this contract. + /// Modifies the code which is used to execute calls to this contract address (`AccountId`). + /// + /// We use this to upgrade the contract logic. We don't do any authorization here, any caller + /// can execute this method. In a production contract you would do some authorization here. #[ink(message)] pub fn set_code(&mut self, code_hash: [u8; 32]) { - ink_env::set_code_hash(&code_hash).expect("Fail to set code."); - ink_env::debug_println!("set code_hash success"); + ink_env::set_code_hash(&code_hash) + .unwrap_or_else(|err| { + panic!( + "Failed to `set_code_hash` to {:?} due to {:?}", + code_hash, err + ) + }); + ink_env::debug_println!("Switched code hash to {:?}.", code_hash); } } } diff --git a/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml b/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml index 051f1587b2b..3356a384db3 100644 --- a/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml +++ b/examples/upgradeable-contracts/set-code-hash/new-increamenter/Cargo.toml @@ -1,23 +1,24 @@ [package] -name = "new-incrementer" -version = "0.1.0" +name = "updated-incrementer" +version = "3.0.1" edition = "2021" -authors = ["Will"] +authors = ["Parity Technologies "] +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ink_primitives = { version = "3.0.0", path = "../../../../crates/primitives", default-features = false } -ink_metadata = { version = "3.0.0", path = "../../../../crates/metadata", default-features = false, features = ["derive"], optional = true } -ink_env = { version = "3.0.0", path = "../../../../crates/env", default-features = false, features = ["ink-debug"] } -ink_storage = { version = "3.0.0", path = "../../../../crates/storage", default-features = false } -ink_lang = { version = "3.0.0", path = "../../../../crates/lang", default-features = false } +ink_primitives = { version = "3.0.1", path = "../../../../crates/primitives", default-features = false } +ink_metadata = { version = "3.0.1", path = "../../../../crates/metadata", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "3.0.1", path = "../../../../crates/env", default-features = false, features = ["ink-debug"] } +ink_storage = { version = "3.0.1", path = "../../../../crates/storage", default-features = false } +ink_lang = { version = "3.0.1", path = "../../../../crates/lang", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } [lib] -name = "new_incrementer" +name = "updated_incrementer" path = "lib.rs" crate-type = ["cdylib"] diff --git a/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs b/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs index ec5ca9a7b47..5786b743362 100644 --- a/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs +++ b/examples/upgradeable-contracts/set-code-hash/new-increamenter/lib.rs @@ -5,6 +5,9 @@ use ink_lang as ink; #[ink::contract] pub mod incrementer { + /// This struct contains the smart contract storage. + /// + /// *Note:* We use exactly the same storage struct as in the originally deployed `incrementer`. #[ink(storage)] pub struct Incrementer { count: u32, @@ -12,6 +15,10 @@ pub mod incrementer { impl Incrementer { /// Creates a new counter smart contract initialized with the given base value. + /// + /// Note that with our upgrade-workflow this constructor will never actually be called, + /// since we merely replace the code used to execute a contract that was already + /// initiated on-chain. #[ink(constructor)] pub fn new(init_value: u32) -> Self { Self { count: init_value } @@ -23,24 +30,35 @@ pub mod incrementer { Self::new(0) } - /// Splice `base` and `target` together. + /// Increments the counter value which is stored in the contract's storage. + /// + /// *Note:* We use a different step size here than in the original `incrementer`. #[ink(message)] pub fn inc(&mut self) { - // Different step size with old contract. self.count += 4; - ink_env::debug_println!("count is {},use new code", self.count); + ink_env::debug_println!("The new count is {}, it was modified using the updated `new_incrementer` code.", self.count); } + /// Returns the counter value which is stored in this contract's storage. #[ink(message)] pub fn get(&self) -> u32 { self.count } - /// Set new code to this contract. + /// Modifies the code which is used to execute calls to this contract address (`AccountId`). + /// + /// We use this to upgrade the contract logic. We don't do any authorization here, any caller + /// can execute this method. In a production contract you would do some authorization here. #[ink(message)] pub fn set_code(&mut self, code_hash: [u8; 32]) { - ink_env::set_code_hash(&code_hash).expect("Fail to set code."); - ink_env::debug_println!("set code_hash success"); + ink_env::set_code_hash(&code_hash) + .unwrap_or_else(|err| { + panic!( + "Failed to `set_code_hash` to {:?} due to {:?}", + code_hash, err + ) + }); + ink_env::debug_println!("Switched code hash to {:?}.", code_hash); } } }