From 27ff70915101fce85f7e3db85a714a8bc95e7af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Mon, 15 Jan 2024 13:45:22 +0100 Subject: [PATCH 1/2] Unify WasmVersion into concordium_contracts_common --- .../concordium_base/src/smart_contracts.rs | 45 +---------- .../concordium-contracts-common/src/types.rs | 79 +++++++++++++++++++ .../wasm-chain-integration/src/utils.rs | 35 +------- 3 files changed, 82 insertions(+), 77 deletions(-) diff --git a/rust-src/concordium_base/src/smart_contracts.rs b/rust-src/concordium_base/src/smart_contracts.rs index 5a62cc41f..25151fefa 100644 --- a/rust-src/concordium_base/src/smart_contracts.rs +++ b/rust-src/concordium_base/src/smart_contracts.rs @@ -6,6 +6,7 @@ use crate::{ }, constants::*, }; +pub use concordium_contracts_common::WasmVersion; /// Re-export of common helper functionality for smart contract, such as types /// and serialization specific for smart contracts. pub use concordium_contracts_common::{ @@ -25,48 +26,6 @@ use std::convert::{TryFrom, TryInto}; )] pub type Parameter = OwnedParameter; -#[derive( - SerdeSerialize, SerdeDeserialize, Debug, Copy, Clone, Display, PartialEq, Eq, PartialOrd, Ord, -)] -#[serde(try_from = "u8", into = "u8")] -#[repr(u8)] -/// Version of the module. This determines the chain API that the module can -/// access. -pub enum WasmVersion { - #[display = "V0"] - /// The initial smart contracts version. This has a simple state API that - /// has very limited capacity. `V0` contracts also use message-passing as - /// the interaction method. - V0 = 0u8, - #[display = "V1"] - /// `V1` contracts were introduced with protocol version 4. In comparison to - /// `V0` contracts they use synchronous calls as the interaction method, - /// and they have access to a more fine-grained state API allowing for - /// unlimited (apart from NRG costs) state size. - V1, -} - -/// V0 is the default version of smart contracts. -impl Default for WasmVersion { - fn default() -> Self { Self::V0 } -} - -impl From for u8 { - fn from(x: WasmVersion) -> Self { x as u8 } -} - -impl TryFrom for WasmVersion { - type Error = anyhow::Error; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::V0), - 1 => Ok(Self::V1), - _ => anyhow::bail!("Only versions 0 and 1 of smart contracts are supported."), - } - } -} - impl Serial for WasmVersion { #[inline(always)] fn serial(&self, out: &mut B) { u32::from(u8::from(*self)).serial(out) } @@ -76,7 +35,7 @@ impl Deserial for WasmVersion { fn deserial(source: &mut R) -> ParseResult { let x = u32::deserial(source)?; let tag = u8::try_from(x)?; - tag.try_into() + Ok(tag.try_into()?) } } diff --git a/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs b/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs index 6b29da20e..3118c22f5 100644 --- a/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs +++ b/smart-contracts/contracts-common/concordium-contracts-common/src/types.rs @@ -2491,12 +2491,91 @@ impl fmt::Display for ParseError { #[cfg(feature = "std")] impl std::error::Error for ParseError {} +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u8)] +#[cfg_attr(feature = "derive-serde", derive(SerdeSerialize, SerdeDeserialize))] +#[cfg_attr(feature = "derive-serde", serde(try_from = "u8", into = "u8"))] +/// Version of the module. This determines the chain API that the module can +/// access. +pub enum WasmVersion { + /// The initial smart contracts version. This has a simple state API that + /// has very limited capacity. `V0` contracts also use message-passing as + /// the interaction method. + V0 = 0u8, + /// `V1` contracts were introduced with protocol version 4. In comparison to + /// `V0` contracts they use synchronous calls as the interaction method, + /// and they have access to a more fine-grained state API allowing for + /// unlimited (apart from NRG costs) state size. + V1, +} + +impl fmt::Display for WasmVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + WasmVersion::V0 => f.write_str("V0"), + WasmVersion::V1 => f.write_str("V1"), + } + } +} + +/// V0 is the default version of smart contracts. +impl Default for WasmVersion { + fn default() -> Self { Self::V0 } +} + +impl convert::From for u8 { + fn from(x: WasmVersion) -> Self { x as u8 } +} + #[cfg(feature = "derive-serde")] mod serde_impl { use super::*; use serde::{de, de::Visitor, Deserializer, Serializer}; use std::{fmt, num}; + #[derive(Debug, thiserror::Error)] + #[error("Unsupported version: {unexpected_string}. Only 'V0' and 'V1' are supported.")] + pub struct WasmVersionParseError { + pub unexpected_string: String, + } + + impl str::FromStr for WasmVersion { + type Err = WasmVersionParseError; + + fn from_str(s: &str) -> Result { + match s { + "V0" | "v0" => Ok(WasmVersion::V0), + "V1" | "v1" => Ok(WasmVersion::V1), + unexpected_string => Err(WasmVersionParseError { + unexpected_string: unexpected_string.to_string(), + }), + } + } + } + + #[derive(Debug, thiserror::Error)] + #[error( + "Unsupported version: {unexpected_version}. Only versions 0 and 1 of smart contracts are \ + supported." + )] + pub struct U8WasmVersionConvertError { + pub unexpected_version: u8, + } + + impl TryFrom for WasmVersion { + type Error = U8WasmVersionConvertError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::V0), + 1 => Ok(Self::V1), + unexpected_version => Err(U8WasmVersionConvertError { + unexpected_version, + }), + } + } + } + /// An error that may occur when converting from a string to an exchange /// rate. #[derive(Debug, thiserror::Error)] diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 441913d40..2bc7e6dd3 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -17,39 +17,6 @@ use concordium_wasm::{ use rand::{prelude::*, RngCore}; use std::{collections::BTreeMap, default::Default}; -#[derive(Debug, Clone, Copy)] -pub enum WasmVersion { - V0, - V1, -} - -impl std::str::FromStr for WasmVersion { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s { - "V0" | "v0" => Ok(WasmVersion::V0), - "V1" | "v1" => Ok(WasmVersion::V1), - _ => anyhow::bail!("Unsupported version: '{}'. Only 'V0' and 'V1' are supported.", s), - } - } -} - -impl WasmVersion { - /// Get the version from the cursor. This is not a Serial implementation - /// since it uses big-endian. - pub fn read(source: &mut std::io::Cursor<&[u8]>) -> anyhow::Result { - let mut data = [0u8; 4]; - use std::io::Read; - source.read_exact(&mut data).context("Not enough data to read WasmVersion.")?; - match u32::from_be_bytes(data) { - 0 => Ok(WasmVersion::V0), - 1 => Ok(WasmVersion::V1), - n => bail!("Unsupported Wasm version {}.", n), - } - } -} - /// A host which traps for any function call. pub struct TrapHost; @@ -697,7 +664,7 @@ pub fn get_build_info_from_skeleton( } } let Some(cs) = build_context_section else { - return Err(CustomSectionLookupError::Missing) + return Err(CustomSectionLookupError::Missing); }; let info: VersionedBuildInfo = from_bytes(cs.contents).context("Failed parsing build info")?; Ok(info) From e11cf529496b892619a6c47b8dfb9221f6353a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Mon, 15 Jan 2024 14:32:28 +0100 Subject: [PATCH 2/2] Update changelogs --- rust-src/concordium_base/CHANGELOG.md | 2 ++ smart-contracts/wasm-chain-integration/CHANGELOG.md | 4 ++++ smart-contracts/wasm-chain-integration/src/utils.rs | 1 + 3 files changed, 7 insertions(+) diff --git a/rust-src/concordium_base/CHANGELOG.md b/rust-src/concordium_base/CHANGELOG.md index 126ed4283..7669ab750 100644 --- a/rust-src/concordium_base/CHANGELOG.md +++ b/rust-src/concordium_base/CHANGELOG.md @@ -11,6 +11,8 @@ - Change `Debug` instance of `dodis_yampolskiy_prf::SecretKey` to hide the value. - Remove `Timestamp` to instead reexport the similar type from `concordium_contracts_common`. This adds several new methods, but results in a breaking change in the `serde::Serialize` implementation, which is now using string containing RFC3393 representation instead the underlying milliseconds. +- Remove `smart_contracts::WasmVersion` to instead reexport a similar type from `concordium_contracts_common`. + This adds a `FromStr` implementation and changes the associated type `TryFrom::Error` from `anyhow::Error` to `concordium_contracts_common::U8WasmVersionConvertError`. ## 3.2.0 (2023-11-22) diff --git a/smart-contracts/wasm-chain-integration/CHANGELOG.md b/smart-contracts/wasm-chain-integration/CHANGELOG.md index 32bf913b3..0e3077a90 100644 --- a/smart-contracts/wasm-chain-integration/CHANGELOG.md +++ b/smart-contracts/wasm-chain-integration/CHANGELOG.md @@ -4,6 +4,10 @@ - Add a `branch_statistics` function to get insight into smart contract state tree structure. +- Remove `utils::WasmVersion` to instead reexport a similar type from `concordium_contracts_common`. + This adds `Display`, `Default`, `TryFrom`, `serde::Serialize` and `serde::Deserialize` for `WasmVersion` and `From` for `u8`. + The associated type `FromStr::Err` changes from `anyhow::Error` to `concordium_contracts_common::WasmVersionParseError`. + The method `WasmVersin::read` is removed. ## concordium-smart-contract-engine 3.1.0 (2023-10-18) diff --git a/smart-contracts/wasm-chain-integration/src/utils.rs b/smart-contracts/wasm-chain-integration/src/utils.rs index 2bc7e6dd3..bf9943b00 100644 --- a/smart-contracts/wasm-chain-integration/src/utils.rs +++ b/smart-contracts/wasm-chain-integration/src/utils.rs @@ -3,6 +3,7 @@ use crate::{v1::EmittedDebugStatement, ExecResult}; 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, };