use crate::{
common::{
Buffer, Deserial, Get, ParseResult, ReadBytesExt, SerdeDeserialize, SerdeSerialize, Serial,
Serialize,
},
constants::*,
};
pub use concordium_contracts_common::{
self, ContractName, ExceedsParameterSize, ModuleReference, OwnedContractName, OwnedParameter,
OwnedReceiveName, ReceiveName,
};
use concordium_contracts_common::{AccountAddress, Address, Amount, ContractAddress};
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;
#[derive(
SerdeSerialize, SerdeDeserialize, Debug, Copy, Clone, Display, PartialEq, Eq, PartialOrd, Ord,
)]
#[serde(try_from = "u8", into = "u8")]
#[repr(u8)]
pub enum WasmVersion {
#[display = "V0"]
V0 = 0u8,
#[display = "V1"]
V1,
}
impl Default for WasmVersion {
fn default() -> Self { Self::V0 }
}
impl From<WasmVersion> for u8 {
fn from(x: WasmVersion) -> Self { x as u8 }
}
impl TryFrom<u8> for WasmVersion {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
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<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)?;
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,
},
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct InstanceUpdatedEvent {
#[serde(default)]
pub contract_version: WasmVersion,
pub address: ContractAddress,
pub instigator: Address,
pub amount: Amount,
pub message: OwnedParameter,
pub receive_name: OwnedReceiveName,
pub events: Vec<ContractEvent>,
}
#[derive(SerdeSerialize, SerdeDeserialize, Debug, 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 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)
}
}