From 53ffe2ef5c2e3201f581874cf7e45229ba292015 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 24 Sep 2025 08:06:30 +0200 Subject: [PATCH 1/3] Use correct byte order --- crates/env/src/engine/on_chain/pallet_revive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/engine/on_chain/pallet_revive.rs b/crates/env/src/engine/on_chain/pallet_revive.rs index cf28698b972..5f5cf37c2fb 100644 --- a/crates/env/src/engine/on_chain/pallet_revive.rs +++ b/crates/env/src/engine/on_chain/pallet_revive.rs @@ -964,7 +964,7 @@ impl TypedEnvBackend for EnvInstance { ) .expect("call host function failed"); - U256::from_little_endian(&output[..]) + U256::from_big_endian(&output[..]) } fn emit_event(&mut self, event: &Evt) From acc5368f4879e33bc96be6377cbd7aa38a2e3a56 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 24 Sep 2025 08:07:07 +0200 Subject: [PATCH 2/3] Clean up `system-precompile` example, add test --- .../internal/system-precompile/Cargo.toml | 2 +- .../internal/system-precompile/lib.rs | 376 ++---------------- .../pallet-revive-caller/src/lib.rs | 1 - 3 files changed, 24 insertions(+), 355 deletions(-) diff --git a/integration-tests/internal/system-precompile/Cargo.toml b/integration-tests/internal/system-precompile/Cargo.toml index 4585ba4c66b..1f650a08831 100755 --- a/integration-tests/internal/system-precompile/Cargo.toml +++ b/integration-tests/internal/system-precompile/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "mapping" +name = "system-precompile" version = "6.0.0-alpha.4" authors = ["Use Ink "] edition = "2024" diff --git a/integration-tests/internal/system-precompile/lib.rs b/integration-tests/internal/system-precompile/lib.rs index cf59d8dc87d..54662c18215 100755 --- a/integration-tests/internal/system-precompile/lib.rs +++ b/integration-tests/internal/system-precompile/lib.rs @@ -1,143 +1,28 @@ -//! A smart contract which demonstrates functionality of `Mapping` functions. +//! A smart contract which demonstrates functionality of the +//! `pallet-revive` `System` precompile. #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] -mod mapping { - use ink::{ - U256, - prelude::{ - string::String, - vec::Vec, - }, - storage::Mapping, - }; - - #[derive(Debug, PartialEq)] - #[ink::scale_derive(Encode, Decode, TypeInfo)] - pub enum ContractError { - ValueTooLarge, - } +mod system_precompile { + use ink::U256; /// A contract for testing `Mapping` functionality. #[ink(storage)] #[derive(Default)] - pub struct Mappings { - /// Mapping from owner to number of owned token. - balances: Mapping, - /// Mapping from owner to aliases. - names: Mapping>, - } + pub struct SystemPrecompile {} - impl Mappings { - /// Demonstrates the usage of `Mappings::default()` - /// - /// Creates an empty mapping between accounts and balances. + impl SystemPrecompile { + /// New instance. #[ink(constructor)] pub fn new() -> Self { - let balances = Mapping::default(); - let names = Mapping::default(); - Self { balances, names } - } - - /// Demonstrates the usage of `Mapping::get()`. - /// - /// Returns the balance of an account, or `None` if the account is not in the - /// `Mapping`. - #[ink(message)] - pub fn get_balance(&self) -> Option { - let caller = Self::env().caller(); - self.balances.get(caller) - } - - /// Demonstrates the usage of `Mappings::insert()`. - /// - /// Assigns the value to a given account. - /// - /// Returns the size of the pre-existing balance at the specified key if any. - /// Returns `None` if the account was not previously in the `Mapping`. - #[ink(message)] - pub fn insert_balance(&mut self, value: U256) -> Option { - let caller = Self::env().caller(); - self.balances.insert(caller, &value) - } - - /// Demonstrates the usage of `Mappings::size()`. - /// - /// Returns the size of the pre-existing balance at the specified key if any. - /// Returns `None` if the account was not previously in the `Mapping`. - #[ink(message)] - pub fn size_balance(&mut self) -> Option { - let caller = Self::env().caller(); - self.balances.size(caller) - } - - /// Demonstrates the usage of `Mapping::contains()`. - /// - /// Returns `true` if the account has any balance assigned to it. - #[ink(message)] - pub fn contains_balance(&self) -> bool { - let caller = Self::env().caller(); - self.balances.contains(caller) + Self {} } - /// Demonstrates the usage of `Mappings::remove()`. - /// - /// Removes the balance entry for a given account. + /// Returns the `minimum_balance`. #[ink(message)] - pub fn remove_balance(&mut self) { - let caller = Self::env().caller(); - self.balances.remove(caller); - } - - /// Demonstrates the usage of `Mappings::take()`. - /// - /// Returns the balance of a given account removing it from storage. - /// - /// Returns `None` if the account is not in the `Mapping`. - #[ink(message)] - pub fn take_balance(&mut self) -> Option { - let caller = Self::env().caller(); - self.balances.take(caller) - } - - /// Demonstrates the usage of `Mappings::try_take()` and `Mappings::try_insert()`. - /// - /// Adds a name of a given account. - /// - /// Returns `Ok(None)` if the account is not in the `Mapping`. - /// Returns `Ok(Some(_))` if the account was already in the `Mapping` - /// Returns `Err(_)` if the mapping value couldn't be encoded. - #[ink(message)] - pub fn try_insert_name(&mut self, name: String) -> Result<(), ContractError> { - let caller = Self::env().caller(); - let mut names = match self.names.try_take(caller) { - None => Vec::new(), - Some(value) => value.map_err(|_| ContractError::ValueTooLarge)?, - }; - - names.push(name); - - self.names - .try_insert(caller, &names) - .map_err(|_| ContractError::ValueTooLarge)?; - - Ok(()) - } - - /// Demonstrates the usage of `Mappings::try_get()`. - /// - /// Returns the name of a given account. - /// - /// Returns `Ok(None)` if the account is not in the `Mapping`. - /// Returns `Ok(Some(_))` if the account was already in the `Mapping` - /// Returns `Err(_)` if the mapping value couldn't be encoded. - #[ink(message)] - pub fn try_get_names(&mut self) -> Option, ContractError>> { - let caller = Self::env().caller(); - self.names - .try_get(caller) - .map(|result| result.map_err(|_| ContractError::ValueTooLarge)) + pub fn minimum_balance(&mut self) -> U256 { + self.env().minimum_balance() } } @@ -149,247 +34,32 @@ mod mapping { type E2EResult = std::result::Result>; #[ink_e2e::test] - async fn insert_and_get_works( + async fn minimum_balance_works( mut client: Client, ) -> E2EResult<()> { // given - let mut constructor = MappingsRef::new(); + let mut constructor = SystemPrecompileRef::new(); let contract = client - .instantiate("mapping", &ink_e2e::alice(), &mut constructor) + .instantiate("system-precompile", &ink_e2e::eve(), &mut constructor) .submit() .await .expect("instantiate failed"); - let mut call_builder = contract.call_builder::(); + let mut call_builder = contract.call_builder::(); // when - let insert = call_builder.insert_balance(1_000.into()); - let size = client - .call(&ink_e2e::alice(), &insert) - .submit() - .await - .expect("Calling `insert_balance` failed") - .return_value(); - - // then - let get = call_builder.get_balance(); - let balance = client - .call(&ink_e2e::alice(), &get) + let min = client + .call(&ink_e2e::eve(), &call_builder.minimum_balance()) .dry_run() .await? .return_value(); - assert!(size.is_none()); - assert_eq!(balance, Some(1_000.into())); - - Ok(()) - } - - #[ink_e2e::test] - async fn insert_and_contains_works( - mut client: Client, - ) -> E2EResult<()> { - // given - let mut constructor = MappingsRef::new(); - let contract = client - .instantiate("mapping", &ink_e2e::bob(), &mut constructor) - .submit() - .await - .expect("instantiate failed"); - let mut call_builder = contract.call_builder::(); - - // when - let insert = call_builder.insert_balance(1_000.into()); - let _ = client - .call(&ink_e2e::bob(), &insert) - .submit() - .await - .expect("Calling `insert_balance` failed") - .return_value(); - - // then - let contains = call_builder.contains_balance(); - let is_there = client.call(&ink_e2e::bob(), &contains).dry_run().await?; - assert!(is_there.return_value()); - - Ok(()) - } - - #[ink_e2e::test] - async fn reinsert_works(mut client: Client) -> E2EResult<()> { - // given - let mut constructor = MappingsRef::new(); - let contract = client - .instantiate("mapping", &ink_e2e::charlie(), &mut constructor) - .submit() - .await - .expect("instantiate failed"); - let mut call_builder = contract.call_builder::(); - - // when - let first_insert = call_builder.insert_balance(1_000.into()); - let _ = client - .call(&ink_e2e::charlie(), &first_insert) - .submit() - .await - .expect("Calling `insert_balance` failed") - .return_value(); - - let insert = call_builder.insert_balance(10_000.into()); - let size = client - .call(&ink_e2e::charlie(), &insert) - .submit() - .await - .expect("Calling `insert_balance` failed") - .return_value(); - // then - assert!(size.is_some()); - - let get = call_builder.get_balance(); - let balance = client - .call(&ink_e2e::charlie(), &get) - .dry_run() - .await? - .return_value(); - - assert_eq!(balance, Some(10_000.into())); - - Ok(()) - } - - #[ink_e2e::test] - async fn insert_and_remove_works( - mut client: Client, - ) -> E2EResult<()> { - // given - let mut constructor = MappingsRef::new(); - let contract = client - .instantiate("mapping", &ink_e2e::dave(), &mut constructor) - .submit() - .await - .expect("instantiate failed"); - let mut call_builder = contract.call_builder::(); - - // when - let insert = call_builder.insert_balance(3_000.into()); - let _ = client - .call(&ink_e2e::dave(), &insert) - .submit() - .await - .expect("Calling `insert_balance` failed") - .return_value(); - - let remove = call_builder.remove_balance(); - let _ = client - .call(&ink_e2e::dave(), &remove) - .submit() - .await - .expect("Calling `remove_balance` failed"); - - // then - let get = call_builder.get_balance(); - let balance = client - .call(&ink_e2e::dave(), &get) - .dry_run() - .await? - .return_value(); - - assert_eq!(balance, None); - - Ok(()) - } - - #[ink_e2e::test] - async fn insert_and_take_works( - mut client: Client, - ) -> E2EResult<()> { - // given - let mut constructor = MappingsRef::new(); - let contract = client - .instantiate("mapping", &ink_e2e::eve(), &mut constructor) - .submit() - .await - .expect("instantiate failed"); - let mut call_builder = contract.call_builder::(); - - // when - let insert = call_builder.insert_balance(4_000.into()); - let _ = client - .call(&ink_e2e::eve(), &insert) - .submit() - .await - .expect("Calling `insert_balance` failed") - .return_value(); - - let take = call_builder.take_balance(); - let balance = client - .call(&ink_e2e::eve(), &take) - .submit() - .await - .expect("Calling `take_balance` failed") - .return_value(); - - // then - assert_eq!(balance, Some(4_000.into())); - - let contains = call_builder.contains_balance(); - let is_there = client - .call(&ink_e2e::eve(), &contains) - .dry_run() - .await? - .return_value(); - - assert!(!is_there); - - Ok(()) - } - - #[ignore] - #[ink_e2e::test] - async fn fallible_storage_methods_work( - mut client: Client, - ) -> E2EResult<()> { - // Makes testing the fallible storage methods more efficient - const ERR: &str = "For this test the env variable `INK_STATIC_BUFFER_SIZE` needs to be set to `256`"; - let buffer_size = std::env::var("INK_STATIC_BUFFER_SIZE") - .unwrap_or_else(|err| panic!("{ERR} {err}")); - assert_eq!(buffer_size, "256", "{ERR}"); - - // given - let mut constructor = MappingsRef::new(); - let contract = client - .instantiate("mapping", &ink_e2e::ferdie(), &mut constructor) - .submit() - .await - .expect("instantiate failed"); - let mut call_builder = contract.call_builder::(); - - // when the mapping value overgrows the buffer - let name = ink_e2e::ferdie().public_key().to_account_id().to_string(); - let insert = call_builder.try_insert_name(name.clone()); - let mut names = Vec::new(); - while let Ok(_) = client.call(&ink_e2e::ferdie(), &insert).submit().await { - names.push(name.clone()) - } - - // then adding another one should fail gracefully - let received_insert_result = client - .call(&ink_e2e::ferdie(), &insert) - .dry_run() - .await? - .return_value(); - let expected_insert_result = - Err(crate::mapping::ContractError::ValueTooLarge); - assert_eq!(received_insert_result, expected_insert_result); - - // then there should be 4 entries (that's what fits into the 256kb buffer) - let received_mapping_value = client - .call(&ink_e2e::ferdie(), &call_builder.try_get_names()) - .dry_run() - .await? - .return_value(); - let expected_mapping_value = Some(Ok(names)); - assert_eq!(received_mapping_value, expected_mapping_value); + // both values are the default values used in the node configurations + // and AssetHub + let native_to_eth_ratio: U256 = 100_000_000.into(); + let existential_deposit: U256 = 1_000_000_000.into(); + let expected = native_to_eth_ratio.saturating_mul(existential_deposit); + assert_eq!(min, expected); Ok(()) } diff --git a/integration-tests/public/runtime-call-contract/sandbox-runtime/pallet-revive-caller/src/lib.rs b/integration-tests/public/runtime-call-contract/sandbox-runtime/pallet-revive-caller/src/lib.rs index bf3acded397..be5081a4afc 100644 --- a/integration-tests/public/runtime-call-contract/sandbox-runtime/pallet-revive-caller/src/lib.rs +++ b/integration-tests/public/runtime-call-contract/sandbox-runtime/pallet-revive-caller/src/lib.rs @@ -12,7 +12,6 @@ use frame_support::{ }; pub use pallet::*; -//type AccountIdOf = ::AccountId; type BalanceOf = <::Currency as Inspect< ::AccountId, >>::Balance; From 17be4462f6d98e2968f61e7f892a7f2dd5833ab5 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 24 Sep 2025 08:08:10 +0200 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c43222e2fed..abdba2861da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Marks the `pallet-revive` host function `account_id` stable - [#2578](https://github.com/use-ink/ink/pull/2578) - Stabilize `is_contract` - [#2654](https://github.com/use-ink/ink/pull/2654) +### Fixed +- Fix decoding of `HostFn::minimum_balance` return value - [#2656](https://github.com/use-ink/ink/pull/2656) + ### Fixed - `name` override fixes for message id computation and trait definitions - [#2649](https://github.com/use-ink/ink/pull/2649)