Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7d05f4b
feat: more granular number types
shumkov Feb 11, 2025
2a6c732
feat: detect type using enum keyword
shumkov Feb 11, 2025
5d4930e
refactor: accept entire contract config to `try_from_schema`
shumkov Feb 12, 2025
fc8dc72
test: fix tests
shumkov Feb 12, 2025
b776185
feat: parse numeric types according to config
shumkov Feb 13, 2025
380948c
fix: missing known version
shumkov Feb 13, 2025
a3fb073
chore: kick off CI
shumkov Feb 13, 2025
e76f575
fix: metadata deserialization in JS client
shumkov Feb 13, 2025
959dcfc
fix: decryption bounded key option read
shumkov Feb 13, 2025
ef60e3b
Merge branch 'v2.0-dev' into feat/granular-data-contract-types
shumkov Feb 14, 2025
b83c12f
revert: changes from another branch
shumkov Feb 17, 2025
722a632
test: fix tests
shumkov Feb 17, 2025
5c64fc5
test: update wasm dpp tests
shumkov Feb 17, 2025
ca5f335
test: fix rs sdk tests
shumkov Feb 17, 2025
e946b2f
fix: invalid feature flag usage
shumkov Feb 17, 2025
0dbfeec
test: update drive abci tests
shumkov Feb 17, 2025
565fba5
refactor: add imports only for state-transition-signing flag
shumkov Feb 19, 2025
67231d1
refactor: add more imports only for state-transition-signing flag
shumkov Feb 19, 2025
b162f85
refactor: remove unnecessary if condition
shumkov Feb 19, 2025
818e0ec
Merge branch 'v2.0-dev' into feat/granular-data-contract-types
shumkov Feb 20, 2025
429cd14
Merge branch 'v2.0-dev' into feat/granular-data-contract-types
shumkov Feb 20, 2025
3c6a76a
Merge branch 'v2.0-dev' into feat/granular-data-contract-types
QuantumExplorer Mar 11, 2025
1dd19d3
Merge branch 'v2.0-dev' into feat/granular-data-contract-types
QuantumExplorer Mar 11, 2025
77558f2
refactor: rename granular types to sized types
shumkov Mar 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_SIZED_INTEGER_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 SIZED_INTEGER_TYPES: &str = "sized_integer_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 sized_integer_types(&self) -> bool {
match self {
DataContractConfig::V0(_) => false,
DataContractConfig::V1(v1) => v1.sized_integer_types,
}
}
}

impl DataContractConfigSettersV1 for DataContractConfig {
fn set_sized_integer_types_enabled(&mut self, enable: bool) {
match self {
DataContractConfig::V0(_) => {}
DataContractConfig::V1(v1) => v1.sized_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_SIZED_INTEGER_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 sized integer Rust types for `integer` property type based on validation rules
pub sized_integer_types: bool,
}

/// Trait representing getters for `DataContractConfigV1`
pub trait DataContractConfigGettersV1: DataContractConfigGettersV0 {
/// Use sized integer Rust types for `integer` property type based on validation rules
fn sized_integer_types(&self) -> bool;
}

/// Trait representing setters for `DataContractConfigV1`
pub trait DataContractConfigSettersV1: DataContractConfigSettersV0 {
/// Enable/disable sized integer Rust types for `integer` property type
fn set_sized_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,
sized_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_DECRYPTION_BOUNDED_KEY)?
.map(|int| int.try_into())
.transpose()?;

let sized_integer_types = contract
.get_optional_bool(config::property::SIZED_INTEGER_TYPES)?
.unwrap_or(DEFAULT_SIZED_INTEGER_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,
sized_integer_types,
})
}
}
Loading