Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ pub(super) fn validate_max_depth_v0(

#[cfg(test)]
mod test {
use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;
use serde_json::json;

use super::*;
Expand Down Expand Up @@ -340,4 +342,30 @@ mod test {

assert_eq!(found_depth, 4);
}

#[test]
fn should_return_error_when_max_depth_exceeded() {
let platform_version = PlatformVersion::first();
let max_depth = platform_version
.dpp
.contract_versions
.document_type_versions
.schema
.max_depth as usize;

let mut inner = json!({ "type": "string" });
for _ in 0..max_depth {
inner = json!({ "a": inner });
}
let schema: Value = inner.into();

let result = validate_max_depth_v0(&schema, platform_version);

let Some(ConsensusError::BasicError(BasicError::DataContractMaxDepthExceedError(e))) =
result.errors.first()
else {
panic!("expected DataContractMaxDepthExceedError");
};
assert_eq!(e.max_depth(), max_depth);
}
}
201 changes: 201 additions & 0 deletions packages/rs-dpp/src/data_contract/group/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ mod tests {

mod validate {
use super::*;
use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;

#[test]
fn test_group_with_all_unilateral_members() {
Expand All @@ -200,5 +202,204 @@ mod tests {

assert!(result.is_valid());
}

#[test]
fn test_group_exceeds_max_members() {
let platform_version = PlatformVersion::latest();
let max = platform_version.system_limits.max_contract_group_size as u32;

let mut members = BTreeMap::new();
for i in 0..=max {
let mut id_bytes = [0u8; 32];
id_bytes[0..4].copy_from_slice(&i.to_le_bytes());
members.insert(Identifier::new(id_bytes), 1);
}

let group = GroupV0 {
members,
required_power: 1,
};

let result = group
.validate(None, platform_version)
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupExceedsMaxMembersError(_))) =
result.errors.first()
else {
panic!("expected GroupExceedsMaxMembersError");
};
}

#[test]
fn test_group_too_few_members_zero() {
let group = GroupV0 {
members: BTreeMap::new(),
required_power: 1,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupHasTooFewMembersError(_))) =
result.errors.first()
else {
panic!("expected GroupHasTooFewMembersError");
};
}

#[test]
fn test_group_too_few_members_one() {
let group = GroupV0 {
members: [(Identifier::random(), 1)].into(),
required_power: 1,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupHasTooFewMembersError(_))) =
result.errors.first()
else {
panic!("expected GroupHasTooFewMembersError");
};
}

#[test]
fn test_group_member_has_power_of_zero() {
let group = GroupV0 {
members: [(Identifier::random(), 0), (Identifier::random(), 1)].into(),
required_power: 1,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupMemberHasPowerOfZeroError(_))) =
result.errors.first()
else {
panic!("expected GroupMemberHasPowerOfZeroError");
};
}

#[test]
fn test_group_member_power_over_limit() {
let group = GroupV0 {
members: [(Identifier::random(), 65_536), (Identifier::random(), 1)].into(),
required_power: 65_536,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_))) =
result.errors.first()
else {
panic!("expected GroupMemberHasPowerOverLimitError");
};
}

#[test]
fn test_group_member_power_exceeds_required() {
let group = GroupV0 {
members: [(Identifier::random(), 6), (Identifier::random(), 5)].into(),
required_power: 5,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_))) =
result.errors.first()
else {
panic!("expected GroupMemberHasPowerOverLimitError");
};
}

#[test]
fn test_group_total_power_less_than_required() {
let group = GroupV0 {
members: [(Identifier::random(), 2), (Identifier::random(), 2)].into(),
required_power: 5,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupTotalPowerLessThanRequiredError(
_,
))) = result.errors.first()
else {
panic!("expected GroupTotalPowerLessThanRequiredError");
};
}

#[test]
fn test_group_non_unilateral_member_power_less_than_required() {
let group = GroupV0 {
members: [(Identifier::random(), 10), (Identifier::random(), 5)].into(),
required_power: 10,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(
BasicError::GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError(_),
)) = result.errors.first()
else {
panic!("expected GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError");
};
}

#[test]
fn test_group_required_power_zero() {
let group = GroupV0 {
members: [(Identifier::random(), 1), (Identifier::random(), 1)].into(),
required_power: 0,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

// Required power of zero is currently intercepted by the per-member `power > required_power`
// check before `GroupRequiredPowerIsInvalidError` is evaluated.
let Some(ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_))) =
result.errors.first()
else {
panic!("expected GroupMemberHasPowerOverLimitError");
};
}
Comment thread
QuantumExplorer marked this conversation as resolved.

#[test]
fn test_group_required_power_over_limit() {
let group = GroupV0 {
members: [
(Identifier::random(), 65_535),
(Identifier::random(), 65_535),
(Identifier::random(), 65_535),
]
.into(),
required_power: 65_536,
};

let result = group
.validate(None, PlatformVersion::latest())
.expect("should not error");

let Some(ConsensusError::BasicError(BasicError::GroupRequiredPowerIsInvalidError(_))) =
result.errors.first()
else {
panic!("expected GroupRequiredPowerIsInvalidError");
};
}
}
}
55 changes: 54 additions & 1 deletion packages/rs-dpp/src/identity/identity_nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,63 @@ mod tests {
use crate::consensus::state::state_error::StateError;
use crate::consensus::ConsensusError;
use crate::identity::identity_nonce::{
validate_identity_nonce_update, MergeIdentityNonceResult,
validate_identity_nonce_update, validate_new_identity_nonce, MergeIdentityNonceResult,
MISSING_IDENTITY_REVISIONS_MAX_BYTES,
};
use platform_value::Identifier;

#[test]
fn validate_new_identity_nonce_valid_zero() {
let result = validate_new_identity_nonce(0, Identifier::default());
assert!(result.errors.is_empty());
}

#[test]
fn validate_new_identity_nonce_valid_max_minus_one() {
let nonce = MISSING_IDENTITY_REVISIONS_MAX_BYTES - 1;
let result = validate_new_identity_nonce(nonce, Identifier::default());
assert!(result.errors.is_empty());
}

#[test]
fn validate_new_identity_nonce_invalid_at_max() {
let nonce = MISSING_IDENTITY_REVISIONS_MAX_BYTES;
let result = validate_new_identity_nonce(nonce, Identifier::default());

let Some(ConsensusError::StateError(StateError::InvalidIdentityNonceError(e))) =
result.errors.first()
else {
panic!("expected state error");
};
assert_eq!(e.error, MergeIdentityNonceResult::NonceTooFarInPast);
}

#[test]
fn validate_new_identity_nonce_invalid_above_max() {
let nonce = MISSING_IDENTITY_REVISIONS_MAX_BYTES + 1;
let result = validate_new_identity_nonce(nonce, Identifier::default());

let Some(ConsensusError::StateError(StateError::InvalidIdentityNonceError(e))) =
result.errors.first()
else {
panic!("expected state error");
};
assert_eq!(e.error, MergeIdentityNonceResult::NonceTooFarInPast);
}

#[test]
fn validate_new_identity_nonce_invalid_large() {
let nonce = 1000;
let result = validate_new_identity_nonce(nonce, Identifier::default());

let Some(ConsensusError::StateError(StateError::InvalidIdentityNonceError(e))) =
result.errors.first()
else {
panic!("expected state error");
};
assert_eq!(e.error, MergeIdentityNonceResult::NonceTooFarInPast);
}

#[test]
fn validate_identity_nonce_not_changed() {
let tip = 50;
Expand Down
Loading