use alloc::{boxed::Box, vec::Vec};
use core::{
convert::TryFrom,
fmt::{Debug, Display, Formatter},
};
use failure::Fail;
use hex_fmt::HexFmt;
use crate::{
bytesrepr::{Error, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
CLType, CLTyped, URef, UREF_SERIALIZED_LENGTH,
};
pub const PURSE_ID_SERIALIZED_LENGTH: usize = UREF_SERIALIZED_LENGTH;
#[doc(hidden)]
#[derive(Debug, Eq, PartialEq)]
pub struct TryFromIntError(());
#[derive(Debug)]
pub struct TryFromSliceForPublicKeyError(());
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct PurseId(URef);
impl PurseId {
pub fn new(uref: URef) -> Self {
PurseId(uref)
}
pub fn value(&self) -> URef {
self.0
}
}
impl From<PurseId> for URef {
fn from(purse_id: PurseId) -> URef {
purse_id.value()
}
}
impl ToBytes for PurseId {
fn to_bytes(&self) -> Result<Vec<u8>, Error> {
ToBytes::to_bytes(&self.0)
}
}
impl FromBytes for PurseId {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
<URef>::from_bytes(bytes).map(|(uref, rem)| (PurseId::new(uref), rem))
}
}
impl CLTyped for PurseId {
fn cl_type() -> CLType {
CLType::URef
}
}
#[repr(u32)]
pub enum ActionType {
Deployment = 0,
KeyManagement = 1,
}
#[doc(hidden)]
impl TryFrom<u32> for ActionType {
type Error = TryFromIntError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
d if d == ActionType::Deployment as u32 => Ok(ActionType::Deployment),
d if d == ActionType::KeyManagement as u32 => Ok(ActionType::KeyManagement),
_ => Err(TryFromIntError(())),
}
}
}
#[repr(i32)]
#[derive(Debug, Fail, PartialEq, Eq)]
pub enum SetThresholdFailure {
#[fail(display = "New threshold should be greater than or equal to deployment threshold")]
KeyManagementThreshold = 1,
#[fail(display = "New threshold should be lower than or equal to key management threshold")]
DeploymentThreshold = 2,
#[fail(display = "Unable to set action threshold due to insufficient permissions")]
PermissionDeniedError = 3,
#[fail(
display = "New threshold should be lower or equal than total weight of associated keys"
)]
InsufficientTotalWeight = 4,
}
#[doc(hidden)]
impl TryFrom<i32> for SetThresholdFailure {
type Error = TryFromIntError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
d if d == SetThresholdFailure::KeyManagementThreshold as i32 => {
Ok(SetThresholdFailure::KeyManagementThreshold)
}
d if d == SetThresholdFailure::DeploymentThreshold as i32 => {
Ok(SetThresholdFailure::DeploymentThreshold)
}
d if d == SetThresholdFailure::PermissionDeniedError as i32 => {
Ok(SetThresholdFailure::PermissionDeniedError)
}
d if d == SetThresholdFailure::InsufficientTotalWeight as i32 => {
Ok(SetThresholdFailure::InsufficientTotalWeight)
}
_ => Err(TryFromIntError(())),
}
}
}
pub const MAX_ASSOCIATED_KEYS: usize = 10;
pub const WEIGHT_SERIALIZED_LENGTH: usize = U8_SERIALIZED_LENGTH;
#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Debug)]
pub struct Weight(u8);
impl Weight {
pub fn new(weight: u8) -> Weight {
Weight(weight)
}
pub fn value(self) -> u8 {
self.0
}
}
impl ToBytes for Weight {
fn to_bytes(&self) -> Result<Vec<u8>, Error> {
ToBytes::to_bytes(&self.0)
}
}
impl FromBytes for Weight {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
let (byte, rem): (u8, &[u8]) = FromBytes::from_bytes(bytes)?;
Ok((Weight::new(byte), rem))
}
}
impl CLTyped for Weight {
fn cl_type() -> CLType {
CLType::U8
}
}
pub const PUBLIC_KEY_LENGTH: usize = 32;
pub const PUBLIC_KEY_SERIALIZED_LENGTH: usize = PUBLIC_KEY_LENGTH;
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy)]
pub struct PublicKey([u8; PUBLIC_KEY_LENGTH]);
impl Display for PublicKey {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "PublicKey({})", HexFmt(&self.0))
}
}
impl PublicKey {
pub fn new(key: [u8; PUBLIC_KEY_LENGTH]) -> PublicKey {
PublicKey(key)
}
pub fn value(self) -> [u8; PUBLIC_KEY_LENGTH] {
self.0
}
pub fn to_vec(&self) -> Vec<u8> {
self.0.to_vec()
}
}
impl Debug for PublicKey {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "{}", self)
}
}
impl CLTyped for PublicKey {
fn cl_type() -> CLType {
CLType::FixedList(Box::new(CLType::U8), PUBLIC_KEY_LENGTH as u32)
}
}
impl From<[u8; PUBLIC_KEY_LENGTH]> for PublicKey {
fn from(key: [u8; PUBLIC_KEY_LENGTH]) -> Self {
PublicKey(key)
}
}
impl TryFrom<&[u8]> for PublicKey {
type Error = TryFromSliceForPublicKeyError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != PUBLIC_KEY_LENGTH {
return Err(TryFromSliceForPublicKeyError(()));
}
let mut public_key = [0u8; 32];
public_key.copy_from_slice(bytes);
Ok(PublicKey::new(public_key))
}
}
impl ToBytes for PublicKey {
fn to_bytes(&self) -> Result<Vec<u8>, Error> {
ToBytes::to_bytes(&self.0)
}
}
impl FromBytes for PublicKey {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
let (key_bytes, rem): ([u8; PUBLIC_KEY_LENGTH], &[u8]) = FromBytes::from_bytes(bytes)?;
Ok((PublicKey::new(key_bytes), rem))
}
}
#[derive(PartialEq, Eq, Fail, Debug)]
#[repr(i32)]
pub enum AddKeyFailure {
#[fail(display = "Unable to add new associated key because maximum amount of keys is reached")]
MaxKeysLimit = 1,
#[fail(display = "Unable to add new associated key because given key already exists")]
DuplicateKey = 2,
#[fail(display = "Unable to add new associated key due to insufficient permissions")]
PermissionDenied = 3,
}
#[doc(hidden)]
impl TryFrom<i32> for AddKeyFailure {
type Error = TryFromIntError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
d if d == AddKeyFailure::MaxKeysLimit as i32 => Ok(AddKeyFailure::MaxKeysLimit),
d if d == AddKeyFailure::DuplicateKey as i32 => Ok(AddKeyFailure::DuplicateKey),
d if d == AddKeyFailure::PermissionDenied as i32 => Ok(AddKeyFailure::PermissionDenied),
_ => Err(TryFromIntError(())),
}
}
}
#[derive(Fail, Debug, Eq, PartialEq)]
#[repr(i32)]
pub enum RemoveKeyFailure {
#[fail(display = "Unable to remove a key that does not exist")]
MissingKey = 1,
#[fail(display = "Unable to remove associated key due to insufficient permissions")]
PermissionDenied = 2,
#[fail(display = "Unable to remove a key which would violate action threshold constraints")]
ThresholdViolation = 3,
}
#[doc(hidden)]
impl TryFrom<i32> for RemoveKeyFailure {
type Error = TryFromIntError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
d if d == RemoveKeyFailure::MissingKey as i32 => Ok(RemoveKeyFailure::MissingKey),
d if d == RemoveKeyFailure::PermissionDenied as i32 => {
Ok(RemoveKeyFailure::PermissionDenied)
}
d if d == RemoveKeyFailure::ThresholdViolation as i32 => {
Ok(RemoveKeyFailure::ThresholdViolation)
}
_ => Err(TryFromIntError(())),
}
}
}
#[derive(PartialEq, Eq, Fail, Debug)]
#[repr(i32)]
pub enum UpdateKeyFailure {
#[fail(display = "Unable to update the value under an associated key that does not exist")]
MissingKey = 1,
#[fail(display = "Unable to update associated key due to insufficient permissions")]
PermissionDenied = 2,
#[fail(display = "Unable to update weight that would fall below any of action thresholds")]
ThresholdViolation = 3,
}
#[doc(hidden)]
impl TryFrom<i32> for UpdateKeyFailure {
type Error = TryFromIntError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
d if d == UpdateKeyFailure::MissingKey as i32 => Ok(UpdateKeyFailure::MissingKey),
d if d == UpdateKeyFailure::PermissionDenied as i32 => {
Ok(UpdateKeyFailure::PermissionDenied)
}
d if d == UpdateKeyFailure::ThresholdViolation as i32 => {
Ok(UpdateKeyFailure::ThresholdViolation)
}
_ => Err(TryFromIntError(())),
}
}
}
#[cfg(test)]
mod tests {
use std::{convert::TryFrom, vec::Vec};
use super::*;
#[test]
fn public_key_from_slice() {
let bytes: Vec<u8> = (0..32).collect();
let public_key = PublicKey::try_from(&bytes[..]).expect("should create public key");
assert_eq!(&bytes, &public_key.value());
}
#[test]
fn public_key_from_slice_too_small() {
let _public_key =
PublicKey::try_from(&[0u8; 31][..]).expect_err("should not create public key");
}
#[test]
fn public_key_from_slice_too_big() {
let _public_key =
PublicKey::try_from(&[0u8; 33][..]).expect_err("should not create public key");
}
#[test]
fn try_from_i32_for_set_threshold_failure() {
let max_valid_value_for_variant = SetThresholdFailure::InsufficientTotalWeight as i32;
assert_eq!(
Err(TryFromIntError(())),
SetThresholdFailure::try_from(max_valid_value_for_variant + 1),
"Did you forget to update `SetThresholdFailure::try_from` for a new variant of \
`SetThresholdFailure`, or `max_valid_value_for_variant` in this test?"
);
}
#[test]
fn try_from_i32_for_add_key_failure() {
let max_valid_value_for_variant = AddKeyFailure::PermissionDenied as i32;
assert_eq!(
Err(TryFromIntError(())),
AddKeyFailure::try_from(max_valid_value_for_variant + 1),
"Did you forget to update `AddKeyFailure::try_from` for a new variant of \
`AddKeyFailure`, or `max_valid_value_for_variant` in this test?"
);
}
#[test]
fn try_from_i32_for_remove_key_failure() {
let max_valid_value_for_variant = RemoveKeyFailure::ThresholdViolation as i32;
assert_eq!(
Err(TryFromIntError(())),
RemoveKeyFailure::try_from(max_valid_value_for_variant + 1),
"Did you forget to update `RemoveKeyFailure::try_from` for a new variant of \
`RemoveKeyFailure`, or `max_valid_value_for_variant` in this test?"
);
}
#[test]
fn try_from_i32_for_update_key_failure() {
let max_valid_value_for_variant = UpdateKeyFailure::ThresholdViolation as i32;
assert_eq!(
Err(TryFromIntError(())),
UpdateKeyFailure::try_from(max_valid_value_for_variant + 1),
"Did you forget to update `UpdateKeyFailure::try_from` for a new variant of \
`UpdateKeyFailure`, or `max_valid_value_for_variant` in this test?"
);
}
}