Skip to content

Commit

Permalink
feat: parse numeric types according to config
Browse files Browse the repository at this point in the history
  • Loading branch information
shumkov committed Feb 13, 2025
1 parent fc8dc72 commit b776185
Show file tree
Hide file tree
Showing 9 changed files with 417 additions and 144 deletions.
2 changes: 2 additions & 0 deletions packages/rs-dpp/src/data_contract/config/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub const DEFAULT_CONTRACT_MUTABILITY: bool = true;
pub const DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY: bool = false;
pub const DEFAULT_CONTRACT_DOCUMENT_MUTABILITY: bool = true;
pub const DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED: bool = true;
pub const DEFAULT_GRANULAR_NUMERIC_TYPES: bool = true;

pub mod property {
pub const CAN_BE_DELETED: &str = "canBeDeleted";
Expand All @@ -17,4 +18,5 @@ pub mod property {
"requiresIdentityEncryptionBoundedKey";
pub const REQUIRES_IDENTITY_DECRYPTION_BOUNDED_KEY: &str =
"requiresIdentityDecryptionBoundedKey";
pub const GRANULAR_NUMERIC_TYPES: &str = "granular_numeric_types";
}
55 changes: 52 additions & 3 deletions packages/rs-dpp/src/data_contract/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
mod fields;
mod methods;
pub mod v0;
pub mod v1;

use crate::data_contract::config::v1::{
DataContractConfigGettersV1, DataContractConfigSettersV1, DataContractConfigV1,
};
use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements;
use crate::version::PlatformVersion;
use crate::ProtocolError;
Expand All @@ -18,6 +22,8 @@ use v0::{DataContractConfigGettersV0, DataContractConfigSettersV0, DataContractC
pub enum DataContractConfig {
#[serde(rename = "0")]
V0(DataContractConfigV0),
#[serde(rename = "1")]
V1(DataContractConfigV1),
}

impl DataContractConfig {
Expand All @@ -26,9 +32,10 @@ impl DataContractConfig {
) -> Result<DataContractConfig, ProtocolError> {
match platform_version.dpp.contract_versions.config {
0 => Ok(DataContractConfigV0::default().into()),
1 => Ok(DataContractConfigV1::default().into()),
version => Err(ProtocolError::UnknownVersionMismatch {
method: "DataContractConfig::default_for_version".to_string(),
known_versions: vec![0],
known_versions: vec![0, 1],
received: version,
}),
}
Expand All @@ -43,14 +50,19 @@ impl DataContractConfig {
let config: DataContractConfigV0 = platform_value::from_value(value)?;
Ok(config.into())
}
1 => {
let config: DataContractConfigV1 = platform_value::from_value(value)?;
Ok(config.into())
}
version => Err(ProtocolError::UnknownVersionMismatch {
method: "DataContractConfig::from_value".to_string(),
known_versions: vec![0],
known_versions: vec![0, 1],
received: version,
}),
}
}

// TODO: Remove, it's not using
/// Retrieve contract configuration properties.
///
/// This method takes a BTreeMap representing a contract and retrieves
Expand All @@ -77,9 +89,12 @@ impl DataContractConfig {
0 => Ok(
DataContractConfigV0::get_contract_configuration_properties_v0(contract)?.into(),
),
1 => Ok(
DataContractConfigV1::get_contract_configuration_properties_v1(contract)?.into(),
),
version => Err(ProtocolError::UnknownVersionMismatch {
method: "DataContractConfig::get_contract_configuration_properties".to_string(),
known_versions: vec![0],
known_versions: vec![0, 1],
received: version,
}),
}
Expand All @@ -90,50 +105,58 @@ impl DataContractConfigGettersV0 for DataContractConfig {
fn can_be_deleted(&self) -> bool {
match self {
DataContractConfig::V0(v0) => v0.can_be_deleted,
DataContractConfig::V1(v1) => v1.can_be_deleted,
}
}

fn readonly(&self) -> bool {
match self {
DataContractConfig::V0(v0) => v0.readonly,
DataContractConfig::V1(v1) => v1.readonly,
}
}

fn keeps_history(&self) -> bool {
match self {
DataContractConfig::V0(v0) => v0.keeps_history,
DataContractConfig::V1(v1) => v1.keeps_history,
}
}

fn documents_keep_history_contract_default(&self) -> bool {
match self {
DataContractConfig::V0(v0) => v0.documents_keep_history_contract_default,
DataContractConfig::V1(v1) => v1.documents_keep_history_contract_default,
}
}

fn documents_mutable_contract_default(&self) -> bool {
match self {
DataContractConfig::V0(v0) => v0.documents_mutable_contract_default,
DataContractConfig::V1(v1) => v1.documents_mutable_contract_default,
}
}

fn documents_can_be_deleted_contract_default(&self) -> bool {
match self {
DataContractConfig::V0(v0) => v0.documents_can_be_deleted_contract_default,
DataContractConfig::V1(v1) => v1.documents_can_be_deleted_contract_default,
}
}

/// Encryption key storage requirements
fn requires_identity_encryption_bounded_key(&self) -> Option<StorageKeyRequirements> {
match self {
DataContractConfig::V0(v0) => v0.requires_identity_encryption_bounded_key,
DataContractConfig::V1(v1) => v1.requires_identity_encryption_bounded_key,
}
}

/// Decryption key storage requirements
fn requires_identity_decryption_bounded_key(&self) -> Option<StorageKeyRequirements> {
match self {
DataContractConfig::V0(v0) => v0.requires_identity_decryption_bounded_key,
DataContractConfig::V1(v1) => v1.requires_identity_decryption_bounded_key,
}
}
}
Expand All @@ -142,36 +165,42 @@ impl DataContractConfigSettersV0 for DataContractConfig {
fn set_can_be_deleted(&mut self, value: bool) {
match self {
DataContractConfig::V0(v0) => v0.can_be_deleted = value,
DataContractConfig::V1(v1) => v1.can_be_deleted = value,
}
}

fn set_readonly(&mut self, value: bool) {
match self {
DataContractConfig::V0(v0) => v0.readonly = value,
DataContractConfig::V1(v1) => v1.readonly = value,
}
}

fn set_keeps_history(&mut self, value: bool) {
match self {
DataContractConfig::V0(v0) => v0.keeps_history = value,
DataContractConfig::V1(v1) => v1.keeps_history = value,
}
}

fn set_documents_keep_history_contract_default(&mut self, value: bool) {
match self {
DataContractConfig::V0(v0) => v0.documents_keep_history_contract_default = value,
DataContractConfig::V1(v1) => v1.documents_keep_history_contract_default = value,
}
}

fn set_documents_can_be_deleted_contract_default(&mut self, value: bool) {
match self {
DataContractConfig::V0(v0) => v0.documents_can_be_deleted_contract_default = value,
DataContractConfig::V1(v1) => v1.documents_can_be_deleted_contract_default = value,
}
}

fn set_documents_mutable_contract_default(&mut self, value: bool) {
match self {
DataContractConfig::V0(v0) => v0.documents_mutable_contract_default = value,
DataContractConfig::V1(v1) => v1.documents_mutable_contract_default = value,
}
}

Expand All @@ -181,6 +210,7 @@ impl DataContractConfigSettersV0 for DataContractConfig {
) {
match self {
DataContractConfig::V0(v0) => v0.requires_identity_encryption_bounded_key = value,
DataContractConfig::V1(v1) => v1.requires_identity_encryption_bounded_key = value,
}
}

Expand All @@ -190,6 +220,25 @@ impl DataContractConfigSettersV0 for DataContractConfig {
) {
match self {
DataContractConfig::V0(v0) => v0.requires_identity_decryption_bounded_key = value,
DataContractConfig::V1(v1) => v1.requires_identity_decryption_bounded_key = value,
}
}
}

impl DataContractConfigGettersV1 for DataContractConfig {
fn granular_integer_types(&self) -> bool {
match self {
DataContractConfig::V0(v0) => false,
DataContractConfig::V1(v1) => v1.granular_integer_types,
}
}
}

impl DataContractConfigSettersV1 for DataContractConfig {
fn set_granular_integer_types_enabled(&mut self, enable: bool) {
match self {
DataContractConfig::V0(_) => {}
DataContractConfig::V1(v1) => v1.granular_integer_types = enable,
}
}
}
157 changes: 157 additions & 0 deletions packages/rs-dpp/src/data_contract/config/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use crate::data_contract::config;
use crate::data_contract::config::v0::{DataContractConfigGettersV0, DataContractConfigSettersV0};
use crate::data_contract::config::{
DataContractConfig, DEFAULT_CONTRACT_CAN_BE_DELETED, DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED,
DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY, DEFAULT_CONTRACT_DOCUMENT_MUTABILITY,
DEFAULT_CONTRACT_KEEPS_HISTORY, DEFAULT_CONTRACT_MUTABILITY, DEFAULT_GRANULAR_NUMERIC_TYPES,
};
use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements;
use crate::ProtocolError;
use bincode::{Decode, Encode};
use platform_value::btreemap_extensions::BTreeValueMapHelper;
use platform_value::Value;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "camelCase", default)]
pub struct DataContractConfigV1 {
/// Can the contract ever be deleted. If the contract is deleted, so should be all
/// documents associated with it. TODO: There should also be a way to "stop" the contract -
/// contract and documents are kept in the system, but no new documents can be added to it
pub can_be_deleted: bool,
/// Is the contract mutable. Means that the document definitions can be changed or new
/// document definitions can be added to the contract
pub readonly: bool,
/// Does the contract keep history when the contract itself changes
pub keeps_history: bool,
/// Do documents in the contract keep history. This is a default for all documents in
/// the contract, but can be overridden by the document itself
pub documents_keep_history_contract_default: bool,
/// Are documents in the contract mutable? This specifies whether the documents can be
/// changed. This is a default for all document types in the contract, but can be
/// overridden by the document type config.
pub documents_mutable_contract_default: bool,
/// Can documents in the contract be deleted? This specifies whether the documents can be
/// deleted. This is a default for all document types in the contract, but can be
/// overridden by the document types itself.
pub documents_can_be_deleted_contract_default: bool,
/// Encryption key storage requirements
pub requires_identity_encryption_bounded_key: Option<StorageKeyRequirements>,
/// Decryption key storage requirements
pub requires_identity_decryption_bounded_key: Option<StorageKeyRequirements>,
/// Use granular integer Rust types for `integer` property type
pub granular_integer_types: bool,
}

/// Trait representing getters for `DataContractConfigV1`
pub trait DataContractConfigGettersV1: DataContractConfigGettersV0 {
/// Use granular integer Rust types for `integer` property type
fn granular_integer_types(&self) -> bool;
}

/// Trait representing setters for `DataContractConfigV1`
pub trait DataContractConfigSettersV1: DataContractConfigSettersV0 {
/// Enable/disable granular integer Rust types for `integer` property type
fn set_granular_integer_types_enabled(&mut self, enable: bool);
}

impl Default for DataContractConfigV1 {
fn default() -> Self {
DataContractConfigV1 {
can_be_deleted: DEFAULT_CONTRACT_CAN_BE_DELETED,
readonly: !DEFAULT_CONTRACT_MUTABILITY,
keeps_history: DEFAULT_CONTRACT_KEEPS_HISTORY,
documents_keep_history_contract_default: DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY,
documents_mutable_contract_default: DEFAULT_CONTRACT_DOCUMENT_MUTABILITY,
documents_can_be_deleted_contract_default: DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED,
requires_identity_encryption_bounded_key: None,
requires_identity_decryption_bounded_key: None,
granular_integer_types: true,
}
}
}

impl DataContractConfigV1 {
pub fn from_value(value: Value) -> Result<Self, ProtocolError> {
platform_value::from_value(value).map_err(ProtocolError::ValueError)
}

pub fn default_with_version() -> DataContractConfig {
Self::default().into()
}
}

impl DataContractConfigV1 {
/// Retrieve contract configuration properties.
///
/// This method takes a BTreeMap representing a contract and retrieves
/// the configuration properties based on the values found in the map.
///
/// The process of retrieving contract configuration properties is versioned,
/// and the version is determined by the platform version parameter.
/// If the version is not supported, an error is returned.
///
/// # Parameters
///
/// * `contract`: BTreeMap representing the contract.
/// * `platform_version`: The platform version being used.
///
/// # Returns
///
/// * `Result<ContractConfig, ProtocolError>`: On success, a ContractConfig.
/// On failure, a ProtocolError.
#[inline(always)]
pub(super) fn get_contract_configuration_properties_v1(
contract: &BTreeMap<String, Value>,
) -> Result<DataContractConfigV1, ProtocolError> {
let keeps_history = contract
.get_optional_bool(config::property::KEEPS_HISTORY)?
.unwrap_or(DEFAULT_CONTRACT_KEEPS_HISTORY);
let can_be_deleted = contract
.get_optional_bool(config::property::CAN_BE_DELETED)?
.unwrap_or(DEFAULT_CONTRACT_CAN_BE_DELETED);

let readonly = contract
.get_optional_bool(config::property::READONLY)?
.unwrap_or(!DEFAULT_CONTRACT_MUTABILITY);

let documents_keep_history_contract_default = contract
.get_optional_bool(config::property::DOCUMENTS_KEEP_HISTORY_CONTRACT_DEFAULT)?
.unwrap_or(DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY);

let documents_mutable_contract_default = contract
.get_optional_bool(config::property::DOCUMENTS_MUTABLE_CONTRACT_DEFAULT)?
.unwrap_or(DEFAULT_CONTRACT_DOCUMENT_MUTABILITY);

let documents_can_be_deleted_contract_default = contract
.get_optional_bool(config::property::DOCUMENTS_CAN_BE_DELETED_CONTRACT_DEFAULT)?
.unwrap_or(DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED);

let requires_identity_encryption_bounded_key = contract
.get_optional_integer::<u8>(config::property::REQUIRES_IDENTITY_ENCRYPTION_BOUNDED_KEY)?
.map(|int| int.try_into())
.transpose()?;

let requires_identity_decryption_bounded_key = contract
.get_optional_integer::<u8>(config::property::REQUIRES_IDENTITY_ENCRYPTION_BOUNDED_KEY)?
.map(|int| int.try_into())
.transpose()?;

let granular_numeric_types = contract
.get_optional_bool(config::property::GRANULAR_NUMERIC_TYPES)?
.unwrap_or(DEFAULT_GRANULAR_NUMERIC_TYPES);

Ok(DataContractConfigV1 {
can_be_deleted,
readonly,
keeps_history,
documents_keep_history_contract_default,
documents_mutable_contract_default,
documents_can_be_deleted_contract_default,
requires_identity_encryption_bounded_key,
requires_identity_decryption_bounded_key,
granular_integer_types: granular_numeric_types,
})
}
}
Loading

0 comments on commit b776185

Please sign in to comment.