From e4aa6ab7489d18b2b3a31e49ac4a0a46c87847c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Thu, 26 Sep 2024 15:21:03 +0200 Subject: [PATCH 01/23] Support get_slot_time in test host --- smart-contracts/wasm-chain-integration/src/utils.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 824a55ffa..8954c9114 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -57,6 +57,8 @@ pub struct TestHost<'a, R, BackingStore> { pub debug_events: Vec, /// In-memory instance state used for state-related host calls. state: InstanceState<'a, BackingStore>, + /// TODO + slot_time: Option, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -69,6 +71,7 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { rng_used: false, debug_events: Vec::new(), state, + slot_time: None, } } } @@ -232,6 +235,16 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host Date: Thu, 3 Oct 2024 11:01:33 +0200 Subject: [PATCH 02/23] Refactored --- .../wasm-chain-integration/src/utils.rs | 132 +++++++++--------- .../wasm-transform/src/artifact.rs | 8 +- 2 files changed, 69 insertions(+), 71 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 8954c9114..e9b3fbf7c 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -8,7 +8,7 @@ use crate::{ use anyhow::{anyhow, bail, ensure, Context}; pub use concordium_contracts_common::WasmVersion; use concordium_contracts_common::{ - self as concordium_std, from_bytes, hashes, schema, Cursor, Deserial, + self as concordium_std, from_bytes, hashes, schema, Cursor, Deserial, SlotTime, }; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, @@ -178,76 +178,70 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { - r.try_fill_bytes(&mut memory[dest..dest + size])?; - } - None => { - bail!("Expected an initialized RNG."); - } + let energy = &mut crate::InterpreterEnergy::new(u64::MAX); + let state = &mut self.state; + + ensure!(f.get_mod_name() == "concordium", "Illegal module name! ({:?})", f.get_mod_name()); + + use host::*; + match f.get_item_name() { + "report_error" => { + let (filename, line, column, msg) = extract_debug(memory, stack)?; + bail!(ReportError::Reported { + filename, + line, + column, + msg + }) } - } else if f.matches("concordium", "debug_print") { - let (filename, line, column, msg) = extract_debug(memory, stack)?; - self.debug_events.push(EmittedDebugStatement { - filename, - line, - column, - msg, - remaining_energy: 0.into(), // debug host does not have energy. - }); - } else if f.matches("concordium", "state_lookup_entry") { - host::state_lookup_entry(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_create_entry") { - host::state_create_entry(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_delete_entry") { - host::state_delete_entry(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_delete_prefix") { - host::state_delete_prefix(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_iterate_prefix") { - host::state_iterator(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_iterator_next") { - host::state_iterator_next(stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_iterator_delete") { - host::state_iterator_delete(stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_iterator_key_size") { - host::state_iterator_key_size(stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_iterator_key_read") { - host::state_iterator_key_read(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_entry_read") { - host::state_entry_read(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_entry_write") { - host::state_entry_write(memory, stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_entry_size") { - host::state_entry_size(stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "state_entry_resize") { - host::state_entry_resize(stack, &mut energy, &mut self.state)?; - } else if f.matches("concordium", "set_slot_time") { - // Read slot time from stack - let slot_time = unsafe { stack.pop_u64() }; - // Store locally in Testhost - self.slot_time = Some(slot_time); - } else if f.matches("concordium", "get_slot_time") { - // Read from TestHost - let slot_time = self.slot_time.context("slot_time is not set")?; - // Put on stack - stack.push_value(slot_time); - } else { - bail!("Unsupported host function call.") + "get_random" => { + let size = unsafe { stack.pop_u32() } as usize; + let dest = unsafe { stack.pop_u32() } as usize; + ensure!(dest + size <= memory.len(), "Illegal memory access."); + self.rng_used = true; + self.rng + .as_mut() + .context("Expected an initialized RNG.")? + .try_fill_bytes(&mut memory[dest..dest + size])? + } + "debug_print" => { + let (filename, line, column, msg) = extract_debug(memory, stack)?; + self.debug_events.push(EmittedDebugStatement { + filename, + line, + column, + msg, + remaining_energy: 0.into(), // debug host does not have energy. + }); + } + "state_lookup_entry" => state_lookup_entry(memory, stack, energy, state)?, + "state_create_entry" => state_create_entry(memory, stack, energy, state)?, + "state_delete_entry" => state_delete_entry(memory, stack, energy, state)?, + "state_delete_prefix" => state_delete_prefix(memory, stack, energy, state)?, + "state_iterate_prefix" => state_iterator(memory, stack, energy, state)?, + "state_iterator_next" => state_iterator_next(stack, energy, state)?, + "state_iterator_delete" => state_iterator_delete(stack, energy, state)?, + "state_iterator_key_size" => state_iterator_key_size(stack, energy, state)?, + "state_iterator_key_read" => state_iterator_key_read(memory, stack, energy, state)?, + "state_entry_read" => state_entry_read(memory, stack, energy, state)?, + "state_entry_write" => state_entry_write(memory, stack, energy, state)?, + "state_entry_size" => state_entry_size(stack, energy, state)?, + "state_entry_resize" => state_entry_resize(stack, energy, state)?, + "set_slot_time" => { + // Read slot time from stack + let slot_time = unsafe { stack.pop_u64() }; + // Store locally in Testhost + self.slot_time = Some(slot_time); + } + "get_slot_time" => { + // Read from TestHost + let slot_time = self.slot_time.context("slot_time is not set")?; + // Put on stack + stack.push_value(slot_time); + } + item_name => bail!("Unsupported host function call ({:?}).", item_name), } + Ok(None) } diff --git a/smart-contracts/wasm-transform/src/artifact.rs b/smart-contracts/wasm-transform/src/artifact.rs index 8237221f1..30f7ee276 100644 --- a/smart-contracts/wasm-transform/src/artifact.rs +++ b/smart-contracts/wasm-transform/src/artifact.rs @@ -248,8 +248,12 @@ pub struct ArtifactNamedImport { } impl ArtifactNamedImport { - pub fn matches(&self, mod_name: &str, item_name: &str) -> bool { - self.mod_name.as_ref() == mod_name && self.item_name.as_ref() == item_name + pub fn get_mod_name(&self) -> &str { + self.mod_name.as_ref() + } + + pub fn get_item_name(&self) -> &str { + self.item_name.as_ref() } } From 77945dc72f936f8731b2109b831d1f12fee02aac Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 3 Oct 2024 15:14:55 +0200 Subject: [PATCH 03/23] Added get/set_receive_address --- .gitignore | 4 ++++ .../wasm-chain-integration/src/utils.rs | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 30752c9d6..8b3dbe8aa 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,7 @@ idiss-csharp/*/obj /smart-contracts/rust-contracts/concordium-std/Cargo.lock /smart-contracts/wasm-transform/Cargo.lock + +# Nix +**/*.nix +**/flake.lock diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index e9b3fbf7c..e226398b2 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -8,8 +8,10 @@ use crate::{ use anyhow::{anyhow, bail, ensure, Context}; pub use concordium_contracts_common::WasmVersion; use concordium_contracts_common::{ - self as concordium_std, from_bytes, hashes, schema, Cursor, Deserial, SlotTime, + self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, SeekFrom, SlotTime }; +use concordium_contracts_common::Seek; +use concordium_contracts_common::Serial; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, machine::{self, NoInterrupt, Value}, @@ -59,6 +61,8 @@ pub struct TestHost<'a, R, BackingStore> { state: InstanceState<'a, BackingStore>, /// TODO slot_time: Option, + /// TODO + self_address: Option, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -72,6 +76,7 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { debug_events: Vec::new(), state, slot_time: None, + self_address: None, } } } @@ -239,6 +244,18 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let x = unsafe { stack.pop_u32() }; + let mut y = Cursor::new(memory); + y.seek(SeekFrom::Start(x)).map_err(|_| anyhow!("unable to read bytes at the given position"))?; + self.self_address.context("self_address is not set")?.serial(&mut y).map_err(|_| anyhow!("unable to serialize the self address"))?; + } + "set_receive_self_address" => { + let x = unsafe { stack.pop_u32() }; + let mut y = Cursor::new(memory); + y.seek(SeekFrom::Start(x)).map_err(|_| anyhow!("unable to read bytes at the given position"))?; + self.self_address = Some(ContractAddress::deserial(&mut y)?); + } item_name => bail!("Unsupported host function call ({:?}).", item_name), } From aa91a43d123f923d702f5167d8635a376a745db7 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 3 Oct 2024 15:26:12 +0200 Subject: [PATCH 04/23] Format+clippy --- .../wasm-chain-integration/src/utils.rs | 16 ++++++++++------ smart-contracts/wasm-transform/src/artifact.rs | 8 ++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index e226398b2..870059fb6 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -8,10 +8,9 @@ use crate::{ use anyhow::{anyhow, bail, ensure, Context}; pub use concordium_contracts_common::WasmVersion; use concordium_contracts_common::{ - self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, SeekFrom, SlotTime + self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, Seek, + SeekFrom, Serial, }; -use concordium_contracts_common::Seek; -use concordium_contracts_common::Serial; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, machine::{self, NoInterrupt, Value}, @@ -247,13 +246,18 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { let x = unsafe { stack.pop_u32() }; let mut y = Cursor::new(memory); - y.seek(SeekFrom::Start(x)).map_err(|_| anyhow!("unable to read bytes at the given position"))?; - self.self_address.context("self_address is not set")?.serial(&mut y).map_err(|_| anyhow!("unable to serialize the self address"))?; + y.seek(SeekFrom::Start(x)) + .map_err(|_| anyhow!("unable to read bytes at the given position"))?; + self.self_address + .context("self_address is not set")? + .serial(&mut y) + .map_err(|_| anyhow!("unable to serialize the self address"))?; } "set_receive_self_address" => { let x = unsafe { stack.pop_u32() }; let mut y = Cursor::new(memory); - y.seek(SeekFrom::Start(x)).map_err(|_| anyhow!("unable to read bytes at the given position"))?; + y.seek(SeekFrom::Start(x)) + .map_err(|_| anyhow!("unable to read bytes at the given position"))?; self.self_address = Some(ContractAddress::deserial(&mut y)?); } item_name => bail!("Unsupported host function call ({:?}).", item_name), diff --git a/smart-contracts/wasm-transform/src/artifact.rs b/smart-contracts/wasm-transform/src/artifact.rs index 30f7ee276..8fb04af06 100644 --- a/smart-contracts/wasm-transform/src/artifact.rs +++ b/smart-contracts/wasm-transform/src/artifact.rs @@ -248,13 +248,9 @@ pub struct ArtifactNamedImport { } impl ArtifactNamedImport { - pub fn get_mod_name(&self) -> &str { - self.mod_name.as_ref() - } + pub fn get_mod_name(&self) -> &str { self.mod_name.as_ref() } - pub fn get_item_name(&self) -> &str { - self.item_name.as_ref() - } + pub fn get_item_name(&self) -> &str { self.item_name.as_ref() } } impl TryFromImport for ArtifactNamedImport { From d0fbd3d3531dc24034aabe6b44cff2d584e10ab3 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 3 Oct 2024 16:23:50 +0200 Subject: [PATCH 05/23] Added get/set_receive_self_address and cleaned --- .../wasm-chain-integration/src/utils.rs | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 870059fb6..cc710c3bd 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -58,10 +58,12 @@ pub struct TestHost<'a, R, BackingStore> { pub debug_events: Vec, /// In-memory instance state used for state-related host calls. state: InstanceState<'a, BackingStore>, - /// TODO + /// Time in milliseconds at the beginning of the smart contract's block. slot_time: Option, - /// TODO - self_address: Option, + /// The address of this smart contract + address: Option, + /// The current balance of this smart contract + balance: Option, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -75,7 +77,8 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { debug_events: Vec::new(), state, slot_time: None, - self_address: None, + address: None, + balance: None, } } } @@ -232,33 +235,43 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host state_entry_size(stack, energy, state)?, "state_entry_resize" => state_entry_resize(stack, energy, state)?, "set_slot_time" => { - // Read slot time from stack let slot_time = unsafe { stack.pop_u64() }; - // Store locally in Testhost self.slot_time = Some(slot_time); } "get_slot_time" => { - // Read from TestHost let slot_time = self.slot_time.context("slot_time is not set")?; - // Put on stack stack.push_value(slot_time); } "get_receive_self_address" => { - let x = unsafe { stack.pop_u32() }; - let mut y = Cursor::new(memory); - y.seek(SeekFrom::Start(x)) + let addr_ptr = unsafe { stack.pop_u32() }; + let mut cursor = Cursor::new(memory); + + cursor + .seek(SeekFrom::Start(addr_ptr)) .map_err(|_| anyhow!("unable to read bytes at the given position"))?; - self.self_address + + self.address .context("self_address is not set")? - .serial(&mut y) + .serial(&mut cursor) .map_err(|_| anyhow!("unable to serialize the self address"))?; } "set_receive_self_address" => { - let x = unsafe { stack.pop_u32() }; - let mut y = Cursor::new(memory); - y.seek(SeekFrom::Start(x)) + let addr_ptr = unsafe { stack.pop_u32() }; + let mut cursor = Cursor::new(memory); + + cursor + .seek(SeekFrom::Start(addr_ptr)) .map_err(|_| anyhow!("unable to read bytes at the given position"))?; - self.self_address = Some(ContractAddress::deserial(&mut y)?); + + self.address = Some(ContractAddress::deserial(&mut cursor)?); + } + "get_receive_self_balance" => { + let balance = self.balance.context("no balance was set")?; + stack.push_value(balance); + } + "set_receive_self_balance" => { + let balance = unsafe { stack.pop_u64() }; + self.balance = Some(balance); } item_name => bail!("Unsupported host function call ({:?}).", item_name), } From b3db747f54125eaed9e3af46858ac3dcd901a810 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 3 Oct 2024 16:34:26 +0200 Subject: [PATCH 06/23] changelog --- .../wasm-chain-integration/CHANGELOG.md | 8 +++++++ .../wasm-chain-integration/src/utils.rs | 22 +++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index 7f340ca00..b0d54ab2c 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased changes +- Implemented the following `TestHost` functions: + - `set_slot_time` + - `get_slot_time` + - `set_receive_self_address` + - `get_receive_self_address` + - `set_receive_self_balance` + - `get_receive_self_balance` + ## concordium-smart-contract-engine 6.0.0 (2024-09-09) - Bump `concordium-wasm` to version 5 used by Concordium node version 7.0.0. diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index cc710c3bd..9be3c74c5 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -242,7 +242,7 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + "set_receive_self_address" => { let addr_ptr = unsafe { stack.pop_u32() }; let mut cursor = Cursor::new(memory); @@ -250,12 +250,9 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + "get_receive_self_address" => { let addr_ptr = unsafe { stack.pop_u32() }; let mut cursor = Cursor::new(memory); @@ -263,16 +260,19 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { - let balance = self.balance.context("no balance was set")?; - stack.push_value(balance); + self.address + .context("self_address is not set")? + .serial(&mut cursor) + .map_err(|_| anyhow!("unable to serialize the self address"))?; } "set_receive_self_balance" => { let balance = unsafe { stack.pop_u64() }; self.balance = Some(balance); } + "get_receive_self_balance" => { + let balance = self.balance.context("no balance was set")?; + stack.push_value(balance); + } item_name => bail!("Unsupported host function call ({:?}).", item_name), } From 076d0ecc3cfc568118896ad00c6e8ad00f5becba Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 3 Oct 2024 17:03:12 +0200 Subject: [PATCH 07/23] Accidently removed a public function, undoing that... --- smart-contracts/wasm-transform/src/artifact.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/smart-contracts/wasm-transform/src/artifact.rs b/smart-contracts/wasm-transform/src/artifact.rs index 8fb04af06..53d6cb060 100644 --- a/smart-contracts/wasm-transform/src/artifact.rs +++ b/smart-contracts/wasm-transform/src/artifact.rs @@ -248,6 +248,10 @@ pub struct ArtifactNamedImport { } impl ArtifactNamedImport { + pub fn matches(&self, mod_name: &str, item_name: &str) -> bool { + self.mod_name.as_ref() == mod_name && self.item_name.as_ref() == item_name + } + pub fn get_mod_name(&self) -> &str { self.mod_name.as_ref() } pub fn get_item_name(&self) -> &str { self.item_name.as_ref() } From 6ba3d66d6624d97442b47e2aca8af942b6d63477 Mon Sep 17 00:00:00 2001 From: Rasmus Kirk Date: Fri, 11 Oct 2024 14:58:41 +0000 Subject: [PATCH 08/23] Update smart-contracts/wasm-chain-integration/CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Emil Holm Gjørup --- .../wasm-chain-integration/CHANGELOG.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index b0d54ab2c..68308a8d4 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -2,13 +2,15 @@ ## Unreleased changes -- Implemented the following `TestHost` functions: - - `set_slot_time` - - `get_slot_time` - - `set_receive_self_address` - - `get_receive_self_address` - - `set_receive_self_balance` - - `get_receive_self_balance` +- Support more smart contract host-functions in `TestHost` (used by cargo concordium test): + - `get_slot_time` + - `get_receive_self_address` + - `get_receive_self_balance` + Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: + - `set_slot_time` + - `set_receive_self_address` + - `set_receive_self_balance` + Attempting to get a value before setting it will result in a runtime error. ## concordium-smart-contract-engine 6.0.0 (2024-09-09) From 2508aeb817126a39f7999f6ac7a512063507d3ce Mon Sep 17 00:00:00 2001 From: Rasmus Kirk Date: Fri, 11 Oct 2024 14:58:49 +0000 Subject: [PATCH 09/23] Update smart-contracts/wasm-chain-integration/src/utils.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Emil Holm Gjørup --- smart-contracts/wasm-chain-integration/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 9be3c74c5..01aee30bc 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -188,7 +188,7 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host Date: Fri, 11 Oct 2024 14:58:55 +0000 Subject: [PATCH 10/23] Update smart-contracts/wasm-chain-integration/src/utils.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Emil Holm Gjørup --- smart-contracts/wasm-chain-integration/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 01aee30bc..a1dc5f440 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -273,7 +273,7 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host bail!("Unsupported host function call ({:?}).", item_name), + item_name => bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), f.get_item_name()), } Ok(None) From ba80d06295dc9486f74c6cc88be223f64dc82a5a Mon Sep 17 00:00:00 2001 From: Rasmus Kirk Date: Fri, 11 Oct 2024 14:59:02 +0000 Subject: [PATCH 11/23] Update smart-contracts/wasm-chain-integration/src/utils.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Emil Holm Gjørup --- smart-contracts/wasm-chain-integration/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index a1dc5f440..e45e705f9 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -239,7 +239,7 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { - let slot_time = self.slot_time.context("slot_time is not set")?; + let slot_time = self.slot_time.context("No slot_time is set. Make sure to prepare this in the test environment")?; stack.push_value(slot_time); } "set_receive_self_address" => { From 4adb6f25372e06f5bf933d6ad2624bfd2933d786 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Sat, 12 Oct 2024 16:24:40 +0200 Subject: [PATCH 12/23] Fixed param methods --- .../wasm-chain-integration/src/utils.rs | 91 ++++++++++++++++--- 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index e45e705f9..6d87f73b6 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -11,6 +11,7 @@ use concordium_contracts_common::{ self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, Seek, SeekFrom, Serial, }; +use concordium_std::{HashMap, Read, Write}; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, machine::{self, NoInterrupt, Value}, @@ -60,10 +61,12 @@ pub struct TestHost<'a, R, BackingStore> { state: InstanceState<'a, BackingStore>, /// Time in milliseconds at the beginning of the smart contract's block. slot_time: Option, - /// The address of this smart contract + /// The address of this smart contract. address: Option, - /// The current balance of this smart contract + /// The current balance of this smart contract. balance: Option, + // The parameters of the smart contract. + parameter: HashMap>, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -79,6 +82,7 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { slot_time: None, address: None, balance: None, + parameter: HashMap::default(), } } } @@ -188,7 +192,17 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host machine::Host { - let slot_time = self.slot_time.context("No slot_time is set. Make sure to prepare this in the test environment")?; + let slot_time = self.slot_time.context(unset_err("slot_time"))?; stack.push_value(slot_time); } "set_receive_self_address" => { let addr_ptr = unsafe { stack.pop_u32() }; - let mut cursor = Cursor::new(memory); - cursor - .seek(SeekFrom::Start(addr_ptr)) - .map_err(|_| anyhow!("unable to read bytes at the given position"))?; + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(addr_ptr)).map_err(|_| seek_err)?; self.address = Some(ContractAddress::deserial(&mut cursor)?); } @@ -256,24 +268,73 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { let balance = unsafe { stack.pop_u64() }; self.balance = Some(balance); } "get_receive_self_balance" => { - let balance = self.balance.context("no balance was set")?; + let balance = self.balance.context(unset_err("balance"))?; stack.push_value(balance); } - item_name => bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), f.get_item_name()), + "set_parameter" => { + let param_size = unsafe { stack.pop_u32() }; + let param_ptr = unsafe { stack.pop_u32() }; + let param_index = unsafe { stack.pop_u32() }; + + let mut param = vec![0; param_size as usize]; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(param_ptr)).map_err(|_| seek_err)?; + cursor.read_exact(&mut param)?; + + self.parameter.insert(param_index, param); + } + "get_parameter_size" => { + let param_index = unsafe { stack.pop_u32() }; + + if let Some(param) = self.parameter.get(¶m_index) { + stack.push_value(param.len() as u64) + } else { + stack.push_value(-1i32) + } + } + "get_parameter_section" => { + let offset = unsafe { stack.pop_u32() }; + let length = unsafe { stack.pop_u32() }; + let param_bytes = unsafe { stack.pop_u32() }; + let param_index = unsafe { stack.pop_u32() }; + + if let Some(param) = self.parameter.get(¶m_index) { + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(param_bytes + offset)).map_err(|_| seek_err)?; + + let self_param = param.get(..length as usize).context(format!( + "Tried to grap {} bytes of parameter[{}], which has length {}", + length, + param_index, + param.len() + ))?; + + let bytes_written: i32 = cursor + .write(self_param) + .map_err(|_| anyhow!("Unable to write to given buffer"))? + .try_into()?; + + stack.push_value(bytes_written) + } else { + stack.push_value(-1i32) + } + } + item_name => { + bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) + } } Ok(None) From d7acecf3ee421777df387d935c5fec215ccc67b0 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Wed, 16 Oct 2024 16:38:03 +0200 Subject: [PATCH 13/23] Updated changelog --- smart-contracts/wasm-chain-integration/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index 68308a8d4..a0e550f86 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -6,10 +6,13 @@ - `get_slot_time` - `get_receive_self_address` - `get_receive_self_balance` + - `get_parameter_size` + - `get_parameter_section` Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: - `set_slot_time` - `set_receive_self_address` - `set_receive_self_balance` + - `set_parameter` Attempting to get a value before setting it will result in a runtime error. ## concordium-smart-contract-engine 6.0.0 (2024-09-09) From acb12288ed5409549b37789fdd6e657ed6e47ce5 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 17 Oct 2024 15:33:03 +0200 Subject: [PATCH 14/23] Added support for event logging --- .../wasm-chain-integration/CHANGELOG.md | 21 +++--- .../wasm-chain-integration/src/utils.rs | 69 ++++++++++++++++--- 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index a0e550f86..eaeecd3e0 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -3,17 +3,20 @@ ## Unreleased changes - Support more smart contract host-functions in `TestHost` (used by cargo concordium test): - - `get_slot_time` - - `get_receive_self_address` - - `get_receive_self_balance` - - `get_parameter_size` - - `get_parameter_section` + - `get_slot_time` + - `get_receive_self_address` + - `get_receive_self_balance` + - `get_parameter_size` + - `get_parameter_section` Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: - - `set_slot_time` - - `set_receive_self_address` - - `set_receive_self_balance` - - `set_parameter` + - `set_slot_time` + - `set_receive_self_address` + - `set_receive_self_balance` + - `set_parameter` Attempting to get a value before setting it will result in a runtime error. + The following getters are also created just for the `TestHost`: + - `get_event` + - `get_event_size` ## concordium-smart-contract-engine 6.0.0 (2024-09-09) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 6d87f73b6..92c11a00b 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -65,8 +65,10 @@ pub struct TestHost<'a, R, BackingStore> { address: Option, /// The current balance of this smart contract. balance: Option, - // The parameters of the smart contract. - parameter: HashMap>, + /// The parameters of the smart contract. + parameters: HashMap>, + /// Events logged by the contract + events: Vec>, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -82,7 +84,8 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { slot_time: None, address: None, balance: None, - parameter: HashMap::default(), + parameters: HashMap::default(), + events: Vec::new(), } } } @@ -196,6 +199,7 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host machine::Host { let param_index = unsafe { stack.pop_u32() }; - if let Some(param) = self.parameter.get(¶m_index) { + if let Some(param) = self.parameters.get(¶m_index) { stack.push_value(param.len() as u64) } else { stack.push_value(-1i32) @@ -311,27 +315,70 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let event_length = unsafe { stack.pop_u32() }; + let event_start = unsafe { stack.pop_u32() }; + + // TODO: Log can be full and messages can be too long, but it is unspecified + // what the limits are. Find out, document and fail if either is too long. + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(event_start)).map_err(|_| seek_err)?; + + let mut buf = vec![0; event_length as usize]; + cursor.read(&mut buf).context("Unable to read provided event")?; + + self.events.push(buf); + + stack.push_value(1i32); + } + "get_event_size" => { + let event_index = unsafe { stack.pop_u32() }; + let event_opt = self.events.get(event_index as usize); + + if let Some(event) = event_opt { + let event_size: i32 = event.len().try_into()?; + stack.push_value(event_size) + } else { + stack.push_value(-1i32); + } + } + "get_event" => { + let ret_buf_start = unsafe { stack.pop_u32() }; + let event_index = unsafe { stack.pop_u32() }; + let event_opt = self.events.get(event_index as usize); + + if let Some(event) = event_opt { + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(ret_buf_start)).map_err(|_| seek_err)?; + + let bytes_written: i32 = + cursor.write(event).map_err(|_| anyhow!(write_err))?.try_into()?; + + stack.push_value(bytes_written) + } else { + stack.push_value(-1i32); + } + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From 9ed61dd25710caf84717775f985971c6c9ae937b Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Thu, 17 Oct 2024 17:31:00 +0200 Subject: [PATCH 15/23] Added init_origin functions --- .../wasm-chain-integration/CHANGELOG.md | 2 ++ .../wasm-chain-integration/src/utils.rs | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index eaeecd3e0..88c32ccdd 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -8,11 +8,13 @@ - `get_receive_self_balance` - `get_parameter_size` - `get_parameter_section` + - `get_init_origin` Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: - `set_slot_time` - `set_receive_self_address` - `set_receive_self_balance` - `set_parameter` + - `set_init_origin` Attempting to get a value before setting it will result in a runtime error. The following getters are also created just for the `TestHost`: - `get_event` diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 92c11a00b..8fe9640a0 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -11,7 +11,7 @@ use concordium_contracts_common::{ self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, Seek, SeekFrom, Serial, }; -use concordium_std::{HashMap, Read, Write}; +use concordium_std::{AccountAddress, HashMap, Read, Write}; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, machine::{self, NoInterrupt, Value}, @@ -69,6 +69,8 @@ pub struct TestHost<'a, R, BackingStore> { parameters: HashMap>, /// Events logged by the contract events: Vec>, + /// Address of the sender + init_origin: Option, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -86,6 +88,7 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { balance: None, parameters: HashMap::default(), events: Vec::new(), + init_origin: None, } } } @@ -379,6 +382,25 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let addr_bytes = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(addr_bytes)).map_err(|_| seek_err)?; + + self.init_origin = Some(AccountAddress::deserial(&mut cursor)?); + } + "get_init_origin" => { + let ret_buf_start = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(ret_buf_start)).map_err(|_| seek_err)?; + + self.init_origin + .context(unset_err("init_origin"))? + .serial(&mut cursor) + .map_err(|_| anyhow!(write_err))?; + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From 01fa40e01fef8459cb3e1a9895eaabd06c3df4ee Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Fri, 18 Oct 2024 10:40:36 +0200 Subject: [PATCH 16/23] Completed `receive_invoker` and `receive_sender` --- .../wasm-chain-integration/src/utils.rs | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 8fe9640a0..097c9662b 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -11,7 +11,7 @@ use concordium_contracts_common::{ self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, Seek, SeekFrom, Serial, }; -use concordium_std::{AccountAddress, HashMap, Read, Write}; +use concordium_std::{AccountAddress, HashMap, Read, Write, Address}; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, machine::{self, NoInterrupt, Value}, @@ -67,10 +67,15 @@ pub struct TestHost<'a, R, BackingStore> { balance: Option, /// The parameters of the smart contract. parameters: HashMap>, - /// Events logged by the contract + /// Events logged by the contract. events: Vec>, - /// Address of the sender + /// Account address of the sender. init_origin: Option, + /// Invoker of the top-level transaction. + receive_invoker: Option, + /// Immediate sender of the message. + receive_sender: Option
, + } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -89,6 +94,8 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { parameters: HashMap::default(), events: Vec::new(), init_origin: None, + receive_invoker: None, + receive_sender: None, } } } @@ -401,6 +408,44 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let addr_bytes = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(addr_bytes)).map_err(|_| seek_err)?; + + self.receive_invoker = Some(AccountAddress::deserial(&mut cursor)?); + } + "get_receive_invoker" => { + let ret_buf_start = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(ret_buf_start)).map_err(|_| seek_err)?; + + self.receive_invoker + .context(unset_err("receive_invoker"))? + .serial(&mut cursor) + .map_err(|_| anyhow!(write_err))?; + } + "set_receive_sender" => { + let addr_bytes = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(addr_bytes)).map_err(|_| seek_err)?; + + self.receive_sender = Some(Address::deserial(&mut cursor)?); + } + "get_receive_sender" => { + let ret_buf_start = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(ret_buf_start)).map_err(|_| seek_err)?; + + self.receive_sender + .context(unset_err("receive_sender"))? + .serial(&mut cursor) + .map_err(|_| anyhow!(write_err))?; + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From 6297325116e4e95c4f266069951e3baad7284ee4 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Fri, 18 Oct 2024 13:40:49 +0200 Subject: [PATCH 17/23] Implemented `receive_owner` and `receive_entrypoint` functionality --- .../wasm-chain-integration/CHANGELOG.md | 9 ++ .../wasm-chain-integration/src/utils.rs | 83 +++++++++++++++---- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index 88c32ccdd..f96e5900b 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -9,12 +9,21 @@ - `get_parameter_size` - `get_parameter_section` - `get_init_origin` + - `get_receive_invoker` + - `get_receive_sender` + - `get_receive_owner` + - `get_receive_entrypoint` + - `get_receive_entrypoint_size` Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: - `set_slot_time` - `set_receive_self_address` - `set_receive_self_balance` - `set_parameter` - `set_init_origin` + - `set_receive_invoker` + - `set_receive_sender` + - `set_receive_owner` + - `set_receive_entrypoint` Attempting to get a value before setting it will result in a runtime error. The following getters are also created just for the `TestHost`: - `get_event` diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 097c9662b..b4934a080 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -11,7 +11,7 @@ use concordium_contracts_common::{ self as concordium_std, from_bytes, hashes, schema, ContractAddress, Cursor, Deserial, Seek, SeekFrom, Serial, }; -use concordium_std::{AccountAddress, HashMap, Read, Write, Address}; +use concordium_std::{AccountAddress, Address, HashMap, OwnedEntrypointName, Read, Write}; use concordium_wasm::{ artifact::{Artifact, ArtifactNamedImport, RunnableCode, TryFromImport}, machine::{self, NoInterrupt, Value}, @@ -52,30 +52,33 @@ impl machine::Host for TrapHost { /// generator. pub struct TestHost<'a, R, BackingStore> { /// A RNG for randomised testing. - rng: Option, + rng: Option, /// A flag set to `true` if the RNG was used. - rng_used: bool, + rng_used: bool, /// Debug statements in the order they were emitted. - pub debug_events: Vec, + pub debug_events: Vec, /// In-memory instance state used for state-related host calls. - state: InstanceState<'a, BackingStore>, + state: InstanceState<'a, BackingStore>, /// Time in milliseconds at the beginning of the smart contract's block. - slot_time: Option, + slot_time: Option, /// The address of this smart contract. - address: Option, + address: Option, /// The current balance of this smart contract. - balance: Option, + balance: Option, /// The parameters of the smart contract. - parameters: HashMap>, + parameters: HashMap>, /// Events logged by the contract. - events: Vec>, + events: Vec>, /// Account address of the sender. - init_origin: Option, + init_origin: Option, /// Invoker of the top-level transaction. - receive_invoker: Option, + receive_invoker: Option, /// Immediate sender of the message. - receive_sender: Option
, - + receive_sender: Option
, + /// Owner of the contract. + receive_owner: Option, + /// The receive entrypoint name. + receive_entrypoint: Option, } impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { @@ -96,6 +99,8 @@ impl<'a, R: RngCore, BackingStore> TestHost<'a, R, BackingStore> { init_origin: None, receive_invoker: None, receive_sender: None, + receive_owner: None, + receive_entrypoint: None, } } } @@ -446,6 +451,56 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let addr_bytes = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(addr_bytes)).map_err(|_| seek_err)?; + + self.receive_owner = Some(AccountAddress::deserial(&mut cursor)?); + } + "get_receive_owner" => { + let ret_buf_start = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(ret_buf_start)).map_err(|_| seek_err)?; + + self.receive_owner + .context(unset_err("receive_owner"))? + .serial(&mut cursor) + .map_err(|_| anyhow!(write_err))?; + } + "set_receive_entrypoint" => { + let addr_bytes = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(addr_bytes)).map_err(|_| seek_err)?; + + self.receive_entrypoint = Some(OwnedEntrypointName::deserial(&mut cursor)?); + } + "get_receive_entrypoint_size" => { + let size = self.receive_entrypoint + .as_ref() + .context(unset_err("receive_entrypoint"))? + .as_entrypoint_name() + .size(); + stack.push_value(size); + } + "get_receive_entrypoint" => { + let ret_buf_start = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + cursor.seek(SeekFrom::Start(ret_buf_start)).map_err(|_| seek_err)?; + + let mut bytes = self.receive_entrypoint + .clone() + .context(unset_err("receive_entrypoint"))? + .to_string() + .into_bytes(); + + cursor.write(&mut bytes) + .map_err(|_| anyhow!(write_err))?; + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From 9ad51e286673a5631049727dd610134b19e64658 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Fri, 18 Oct 2024 14:39:09 +0200 Subject: [PATCH 18/23] Implemented `verify_ed25519_signature` --- .../wasm-chain-integration/CHANGELOG.md | 1 + .../wasm-chain-integration/src/utils.rs | 64 ++++++++++++++----- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index f96e5900b..7d0e9e6ec 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -14,6 +14,7 @@ - `get_receive_owner` - `get_receive_entrypoint` - `get_receive_entrypoint_size` + - `verify_ed25519_signature` Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: - `set_slot_time` - `set_receive_self_address` diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index b4934a080..240b4c58c 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -211,7 +211,7 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host machine::Host { + let message_len = unsafe { stack.pop_u32() }; + let message_ptr = unsafe { stack.pop_u32() }; + let signature_ptr = unsafe { stack.pop_u32() }; + let public_key_ptr = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + + cursor.seek(SeekFrom::Start(public_key_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut public_key_bytes = [0; 32]; + cursor.read(&mut public_key_bytes)?; + let z_pk = ed25519_zebra::VerificationKey::try_from(public_key_bytes)?; + + cursor.seek(SeekFrom::Start(signature_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut signature_bytes = [0; 64]; + cursor.read(&mut signature_bytes)?; + let z_sig = ed25519_zebra::Signature::from_bytes(&signature_bytes); + + cursor.seek(SeekFrom::Start(message_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut msg = vec![0; message_len as usize]; + cursor.read(&mut msg)?; + + let is_verified = z_pk.verify(&z_sig, &msg); + + if is_verified.is_ok() { + stack.push_value(1i32) + } else { + stack.push_value(0i32) + } + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From 8277caf0ac5a3dd9efa9841834dd6a045e821b6c Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Tue, 22 Oct 2024 15:52:51 +0200 Subject: [PATCH 19/23] Implemented `verify_ecdsa_secp256k1_signature` in TestHost --- .../wasm-chain-integration/src/utils.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 240b4c58c..b755df3ec 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -531,6 +531,36 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let message_hash_ptr = unsafe { stack.pop_u32() }; + let signature_ptr = unsafe { stack.pop_u32() }; + let public_key_ptr = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + let secp = secp256k1::Secp256k1::verification_only(); + + cursor.seek(SeekFrom::Start(public_key_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut public_key_bytes = [0; 33]; + cursor.read(&mut public_key_bytes)?; + let pk = secp256k1::PublicKey::from_slice(&public_key_bytes)?; + + cursor.seek(SeekFrom::Start(signature_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut signature_bytes = [0; 64]; + cursor.read(&mut signature_bytes)?; + let sig = secp256k1::ecdsa::Signature::from_compact(&signature_bytes)?; + + cursor.seek(SeekFrom::Start(message_hash_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut message_hash_bytes = [0; 32]; + cursor.read(&mut message_hash_bytes)?; + let msg = secp256k1::Message::from_slice(&message_hash_bytes)?; + + let is_verified = secp.verify_ecdsa(&msg, &sig, &pk); + if is_verified.is_ok() { + stack.push_value(1i32) + } else { + stack.push_value(0i32) + } + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From 8f15889c6355d3807453f4111ed7589be17dc7e0 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Tue, 22 Oct 2024 15:55:47 +0200 Subject: [PATCH 20/23] Format --- smart-contracts/wasm-chain-integration/src/utils.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index b755df3ec..6ddf6fdda 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -332,7 +332,9 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host machine::Host { - let size = self.receive_entrypoint + let size = self + .receive_entrypoint .as_ref() .context(unset_err("receive_entrypoint"))? .as_entrypoint_name() @@ -492,14 +495,14 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { let message_len = unsafe { stack.pop_u32() }; From 2cf809b7ceaecfb2f07e15f61d27efb8e15fd37c Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Tue, 22 Oct 2024 17:19:41 +0200 Subject: [PATCH 21/23] Implmented hashing functions - `hash_sha2_256` - `hash_sha3_256` - `hash_keccak_256` --- .../wasm-chain-integration/src/utils.rs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 6ddf6fdda..a2b9c2f9a 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -21,6 +21,7 @@ use concordium_wasm::{ validate::{self, ValidationConfig}, }; use rand::{prelude::*, RngCore}; +use sha2::Digest; use std::{collections::BTreeMap, default::Default}; /// A host which traps for any function call. @@ -564,6 +565,60 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { + let output_ptr = unsafe { stack.pop_u32() }; + let data_len = unsafe { stack.pop_u32() }; + let data_ptr = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + let mut hasher = sha2::Sha256::default(); + + cursor.seek(SeekFrom::Start(data_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut data = vec![0u8; data_len.try_into()?]; + cursor.read(&mut data)?; + + hasher.update(&data); + let mut data_hash = hasher.finalize(); + + cursor.seek(SeekFrom::Start(output_ptr)).map_err(|_| anyhow!(seek_err))?; + cursor.write(&mut data_hash).map_err(|_| anyhow!(write_err))?; + } + "hash_sha3_256" => { + let output_ptr = unsafe { stack.pop_u32() }; + let data_len = unsafe { stack.pop_u32() }; + let data_ptr = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + let mut hasher = sha3::Sha3_256::default(); + + cursor.seek(SeekFrom::Start(data_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut data = vec![0u8; data_len.try_into()?]; + cursor.read(&mut data)?; + + hasher.update(&data); + let mut data_hash = hasher.finalize(); + + cursor.seek(SeekFrom::Start(output_ptr)).map_err(|_| anyhow!(seek_err))?; + cursor.write(&mut data_hash).map_err(|_| anyhow!(write_err))?; + } + "hash_keccak_256" => { + let output_ptr = unsafe { stack.pop_u32() }; + let data_len = unsafe { stack.pop_u32() }; + let data_ptr = unsafe { stack.pop_u32() }; + + let mut cursor = Cursor::new(memory); + let mut hasher = sha3::Keccak256::default(); + + cursor.seek(SeekFrom::Start(data_ptr)).map_err(|_| anyhow!(seek_err))?; + let mut data = vec![0u8; data_len.try_into()?]; + cursor.read(&mut data)?; + + hasher.update(&data); + let mut data_hash = hasher.finalize(); + + cursor.seek(SeekFrom::Start(output_ptr)).map_err(|_| anyhow!(seek_err))?; + cursor.write(&mut data_hash).map_err(|_| anyhow!(write_err))?; + } item_name => { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name) } From f3f333052f55de89eb2bdf740db7ad36abf87a0b Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Tue, 22 Oct 2024 17:22:26 +0200 Subject: [PATCH 22/23] Updated changelog --- smart-contracts/wasm-chain-integration/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index 7d0e9e6ec..5beebf138 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -15,6 +15,10 @@ - `get_receive_entrypoint` - `get_receive_entrypoint_size` - `verify_ed25519_signature` + - `verify_ecdsa_secp256k1_signature` + - `hash_sha2_256` + - `hash_sha3_256` + - `hash_keccak_256` Corresponding new host functions are introduced just for `TestHost` allowing for setting the result of the above: - `set_slot_time` - `set_receive_self_address` From 021f7e33392f1e29d8172e34a978d2d774930d82 Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Tue, 22 Oct 2024 17:27:08 +0200 Subject: [PATCH 23/23] Appeased clippy --- .../wasm-chain-integration/src/utils.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index a2b9c2f9a..9b1d13abf 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -496,14 +496,14 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { let message_len = unsafe { stack.pop_u32() }; @@ -578,10 +578,10 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { let output_ptr = unsafe { stack.pop_u32() }; @@ -596,10 +596,10 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { let output_ptr = unsafe { stack.pop_u32() }; @@ -614,10 +614,10 @@ impl<'a, R: RngCore, BackingStore: trie::BackingStoreLoad> machine::Host { bail!("Unsupported host function call: {:?} {:?}", f.get_mod_name(), item_name)