use crate::{
common::{
Buffer, Deserial, Get, ParseResult, ReadBytesExt, SerdeDeserialize, SerdeSerialize, Serial,
Serialize,
},
constants::*,
};
pub use concordium_contracts_common::WasmVersion;
pub use concordium_contracts_common::{
self, ContractName, ExceedsParameterSize, ModuleReference, OwnedContractName, OwnedParameter,
OwnedReceiveName, ReceiveName,
};
use concordium_contracts_common::{
AccountAddress, Address, Amount, ContractAddress, U8WasmVersionConvertError,
};
use derive_more::*;
use sha2::Digest;
use std::convert::{TryFrom, TryInto};
#[deprecated(
note = "Replaced by [`OwnedParameter`](./struct.OwnedParameter.html) for consistency. Use it \
instead."
)]
pub type Parameter = OwnedParameter;
impl Serial for WasmVersion {
#[inline(always)]
fn serial<B: Buffer>(&self, out: &mut B) {
u32::from(u8::from(*self)).serial(out)
}
}
impl Deserial for WasmVersion {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let x = u32::deserial(source)?;
let tag = u8::try_from(x)?;
Ok(tag.try_into()?)
}
}
#[deprecated(
note = "Replaced by [`ModuleReference`](../hashes/type.ModuleReference.html) for consistency. \
Use it instead."
)]
pub type ModuleRef = ModuleReference;
#[derive(
SerdeSerialize,
SerdeDeserialize,
Serial,
Clone,
Debug,
AsRef,
From,
Into,
PartialOrd,
Ord,
PartialEq,
Eq,
)]
#[serde(transparent)]
pub struct ModuleSource {
#[serde(with = "crate::internal::byte_array_hex")]
#[size_length = 4]
bytes: Vec<u8>,
}
impl ModuleSource {
pub fn size(&self) -> u64 {
self.bytes.len() as u64
}
}
impl Deserial for ModuleSource {
fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
let s: u32 = source.get()?;
anyhow::ensure!(
s <= MAX_WASM_MODULE_SIZE,
"Maximum size of a Wasm module is {}",
MAX_WASM_MODULE_SIZE
);
let bytes = crate::common::deserial_bytes(source, s as usize)?;
Ok(ModuleSource { bytes })
}
}
#[derive(SerdeSerialize, SerdeDeserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct WasmModule {
pub version: WasmVersion,
pub source: ModuleSource,
}
#[derive(Debug, thiserror::Error)]
pub enum WasmFromFileError {
#[error("Failed reading file: {0}")]
Read(#[from] std::io::Error),
#[error("Failed parsing module: {0}")]
Parse(#[from] anyhow::Error),
}
impl WasmModule {
pub fn get_module_ref(&self) -> ModuleReference {
let mut hasher = sha2::Sha256::new();
self.serial(&mut hasher);
ModuleReference::from(<[u8; 32]>::from(hasher.finalize()))
}
pub fn from_file(path: &std::path::Path) -> Result<Self, WasmFromFileError> {
Self::from_slice(&std::fs::read(path)?).map_err(WasmFromFileError::Parse)
}
pub fn from_slice(bytes: &[u8]) -> ParseResult<Self> {
let mut cursor = std::io::Cursor::new(bytes);
let module = super::common::from_bytes(&mut cursor)?;
let remaining = (bytes.len() as u64).saturating_sub(cursor.position());
anyhow::ensure!(
remaining == 0,
"There are {} remaining bytes of data.",
remaining
);
Ok(module)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ContractTraceElement {
Updated { data: InstanceUpdatedEvent },
Transferred {
from: ContractAddress,
amount: Amount,
to: AccountAddress,
},
Interrupted {
address: ContractAddress,
events: Vec<ContractEvent>,
},
Resumed {
address: ContractAddress,
success: bool,
},
Upgraded {
address: ContractAddress,
from: ModuleReference,
to: ModuleReference,
},
}
impl ContractTraceElement {
pub fn affected_address(&self) -> ContractAddress {
match self {
ContractTraceElement::Interrupted { address, .. } => *address,
ContractTraceElement::Resumed { address, .. } => *address,
ContractTraceElement::Upgraded { address, .. } => *address,
ContractTraceElement::Updated {
data: InstanceUpdatedEvent { address, .. },
} => *address,
ContractTraceElement::Transferred { from, .. } => *from,
}
}
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct InstanceUpdatedEvent {
#[serde(default = "WasmVersionInt::zero_version")]
pub contract_version: WasmVersionInt,
pub address: ContractAddress,
pub instigator: Address,
pub amount: Amount,
pub message: OwnedParameter,
pub receive_name: OwnedReceiveName,
pub events: Vec<ContractEvent>,
}
#[derive(SerdeSerialize, SerdeDeserialize, Clone, AsRef, Into, From, PartialEq, Eq)]
#[serde(transparent)]
pub struct ContractEvent {
#[serde(with = "crate::internal::byte_array_hex")]
bytes: Vec<u8>,
}
impl std::fmt::Display for ContractEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for b in &self.bytes {
f.write_fmt(format_args!("{:02x}", b))?
}
Ok(())
}
}
impl std::fmt::Debug for ContractEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
self.bytes.fmt(f)
} else {
for b in &self.bytes {
f.write_fmt(format_args!("{:02x}", b))?
}
Ok(())
}
}
}
impl ContractEvent {
pub fn parse<T: concordium_contracts_common::Deserial>(
&self,
) -> concordium_contracts_common::ParseResult<T> {
use concordium_contracts_common::{Cursor, Get, ParseError};
let mut cursor = Cursor::new(self.as_ref());
let res = cursor.get()?;
if cursor.offset != self.as_ref().len() {
return Err(ParseError::default());
}
Ok(res)
}
}
#[derive(
SerdeSerialize,
SerdeDeserialize,
Debug,
Clone,
PartialEq,
Eq,
Copy,
PartialOrd,
Ord,
Hash,
derive_more::Display,
)]
#[serde(transparent)]
#[repr(transparent)]
#[display(fmt = "V{_0}")]
pub struct WasmVersionInt(pub u8);
impl From<WasmVersion> for WasmVersionInt {
fn from(value: WasmVersion) -> Self {
WasmVersionInt(value as u8)
}
}
impl TryFrom<WasmVersionInt> for WasmVersion {
type Error = U8WasmVersionConvertError;
fn try_from(value: WasmVersionInt) -> Result<Self, Self::Error> {
WasmVersion::try_from(value.0)
}
}
impl WasmVersionInt {
pub const fn zero_version() -> WasmVersionInt {
WasmVersionInt(0)
}
}