Skip to content
Merged
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
6 changes: 3 additions & 3 deletions docs/protocol/moderation-charters.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@ written, the description's 4096-byte cap and the reward split's sum included:
`DocumentPropertyMaxBytesExceededError` (10421), and the `propertyConstraints`
rule `rewardSplitIsWhole` refuses a split that does not add up to 100 with
`DocumentPropertyConstraintViolatedError` (10422). The cap on additions is the
exception (see above). `validate_submitted_charter` in `rs-dpp`
(`packages/rs-dpp/src/moderation_charter/`) only reads a proposal, without
reading state:
exception (see above). `SubmittedCharter::from_document_properties` in
`rs-dpp` (`packages/rs-dpp/src/moderation_charter/`) only reads a proposal,
without reading state:

| Rule | Error | Code |
| --- | --- | --- |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use thiserror::Error;
/// A proposal's reward split does not sum to 100 (11001). No longer produced: the
/// moderation charters contract holds the split to 100 with its `propertyConstraints` rule
/// `rewardSplitIsWhole`, refused as `DocumentPropertyConstraintViolatedError` (10422) on
/// every create, so `validate_submitted_charter` no longer checks it. The variant keeps its
/// place in `BasicError`, whose encoding is positional.
/// every create, and no charter-specific check is left to produce this one. The variant keeps
/// its place in `BasicError`, whose encoding is positional.
#[derive(
Error,
Debug,
Expand Down
66 changes: 7 additions & 59 deletions packages/rs-dpp/src/moderation_charter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,15 @@
//!
//! The schema carries almost every rule through its keywords (references, lookups, key
//! requirements, `distinctFrom`, `maxBytes` for the description's byte cap, and the
//! `propertyConstraints` rule holding the reward split to 100). What it cannot say is here:
//! [`SubmittedCharter`] and [`ElectedCharter`] read the documents' properties, and
//! [`validate_submitted_charter`] reads a proposal. Nothing here reads state.

mod v0;
//! `propertyConstraints` rule holding the reward split to 100). What is here only reads:
//! [`SubmittedCharter`] and [`ElectedCharter`] read the documents' properties. Nothing here
//! reads state.

use crate::balances::credits::Credits;
use crate::consensus::basic::moderation_charter::ModerationCharterMalformedFieldError;
use crate::data_contract::document_type::contested_index_identifier;
use crate::validation::{ConsensusValidationResult, SimpleConsensusValidationResult};
use crate::ProtocolError;
use crate::validation::ConsensusValidationResult;
use platform_value::{Identifier, IdentifierBytes32, Value, ValueMap};
use platform_version::version::PlatformVersion;
use std::collections::{BTreeMap, BTreeSet};

/// The id of the moderation charters system contract, `EG7RGfV8fDTayC2FyVr8HwdpJh3fXDbVztcfE94UmN88`.
Expand Down Expand Up @@ -227,8 +223,9 @@ impl SubmittedCharter {
/// Reads a proposal out of the properties of a `submittedCharter` document.
///
/// The result carries a consensus error, never a proposal, when a property is missing or
/// of the wrong type. The proposal's own rules are checked by
/// [`SubmittedCharter::validate`]; [`validate_submitted_charter`] does both.
/// of the wrong type. The proposal's rules are the contract's own keywords (the reward
/// split's `propertyConstraints` rule `rewardSplitIsWhole`, the description's `maxBytes`),
/// checked wherever the document is validated, not here.
pub fn from_document_properties(
properties: &BTreeMap<String, Value>,
) -> ConsensusValidationResult<Self> {
Expand Down Expand Up @@ -325,33 +322,6 @@ impl SubmittedCharter {
}
properties
}

/// Checks the proposal's own rules. None is left: the reward split's sum is the
/// contract's `propertyConstraints` rule `rewardSplitIsWhole` and the description's
/// 4096-byte cap its `maxBytes`, both checked wherever the document is validated. The
/// versioned step stays for the path that seats a team.
pub fn validate(
&self,
platform_version: &PlatformVersion,
) -> Result<SimpleConsensusValidationResult, ProtocolError> {
match platform_version
.dpp
.validation
.data_contract
.validate_moderation_charter
{
Some(0) => Ok(self.validate_v0()),
Some(version) => Err(ProtocolError::UnknownVersionMismatch {
method: "SubmittedCharter::validate".to_string(),
known_versions: vec![0],
received: version,
}),
None => Err(ProtocolError::NotSupported(format!(
"moderation charters do not exist at protocol version {}",
platform_version.protocol_version
))),
}
}
}

impl ElectedCharter {
Expand Down Expand Up @@ -428,27 +398,5 @@ impl ElectedCharter {
}
}

/// Reads a proposal out of the properties of a `submittedCharter` document and checks its own
/// rules. The result carries the proposal when it passes, and the first error it fails on
/// otherwise.
pub fn validate_submitted_charter(
properties: &BTreeMap<String, Value>,
platform_version: &PlatformVersion,
) -> Result<ConsensusValidationResult<SubmittedCharter>, ProtocolError> {
let result = SubmittedCharter::from_document_properties(properties);
if !result.is_valid_with_data() {
return Ok(ConsensusValidationResult::new_with_errors(result.errors));
}
let charter = result.into_data()?;
let validation = charter.validate(platform_version)?;
if validation.is_valid() {
Ok(ConsensusValidationResult::new_with_data(charter))
} else {
Ok(ConsensusValidationResult::new_with_errors(
validation.errors,
))
}
}

#[cfg(test)]
mod tests;
44 changes: 7 additions & 37 deletions packages/rs-dpp/src/moderation_charter/tests.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use super::{
charter_election_target, moderators_share_of, property_names, validate_submitted_charter,
ElectedCharter, ModerationCharterRewardSplit, SubmittedCharter,
ELECTED_CHARTER_DOCUMENT_TYPE_NAME, FULL_MODERATORS_SHARE, MODERATION_CHARTERS_CONTRACT_ID,
SUBMITTED_CHARTER_DOCUMENT_TYPE_NAME,
charter_election_target, moderators_share_of, property_names, ElectedCharter,
ModerationCharterRewardSplit, SubmittedCharter, ELECTED_CHARTER_DOCUMENT_TYPE_NAME,
FULL_MODERATORS_SHARE, MODERATION_CHARTERS_CONTRACT_ID, SUBMITTED_CHARTER_DOCUMENT_TYPE_NAME,
};
use crate::balances::credits::MAX_CREDITS;
use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;
use platform_value::{Identifier, Value};
use platform_version::version::PlatformVersion;

fn proposal() -> SubmittedCharter {
SubmittedCharter {
Expand All @@ -24,15 +22,6 @@ fn proposal() -> SubmittedCharter {
}
}

fn first_basic_error(
result: &crate::validation::ConsensusValidationResult<SubmittedCharter>,
) -> &BasicError {
match result.errors.first() {
Some(ConsensusError::BasicError(error)) => error,
other => panic!("expected a basic error, got {other:?}"),
}
}

#[test]
fn should_round_trip_a_proposal_through_its_document_properties() {
let proposal = proposal();
Expand Down Expand Up @@ -66,27 +55,14 @@ fn should_read_a_zero_share_as_zero() {
}

#[test]
fn should_accept_a_proposal_without_reasons() {
fn should_read_a_proposal_without_reasons() {
let proposal = SubmittedCharter {
reasons: vec![],
..proposal()
};
let result = validate_submitted_charter(
&proposal.to_document_properties(),
PlatformVersion::latest(),
)
.expect("validation executes");
assert!(result.is_valid_with_data());
}

#[test]
fn should_accept_a_valid_proposal() {
let result = validate_submitted_charter(
&proposal().to_document_properties(),
PlatformVersion::latest(),
)
.expect("validation executes");
assert!(result.is_valid_with_data(), "{:?}", result.errors);
let read = SubmittedCharter::from_document_properties(&proposal.to_document_properties());
assert!(read.is_valid_with_data(), "{:?}", read.errors);
assert_eq!(read.into_data().expect("data"), proposal);
}

#[test]
Expand Down Expand Up @@ -124,12 +100,6 @@ fn should_refuse_a_missing_or_mistyped_property() {
));
}

#[test]
fn should_refuse_to_validate_below_protocol_version_14() {
let platform_version = PlatformVersion::get(13).expect("version 13");
assert!(proposal().validate(platform_version).is_err());
}

#[test]
fn should_round_trip_an_elected_charter_through_its_document_properties() {
let charter = ElectedCharter {
Expand Down
13 changes: 0 additions & 13 deletions packages/rs-dpp/src/moderation_charter/v0/mod.rs

This file was deleted.

9 changes: 4 additions & 5 deletions packages/rs-dpp/src/system_data_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,8 @@ mod moderation_charters_tests {
use crate::document::{Document, DocumentV0Getters, DocumentV0Setters};
use crate::identity::Purpose;
use crate::moderation_charter::{
property_names, validate_submitted_charter, ElectedCharter, ModerationCharterRewardSplit,
SubmittedCharter, ADDED_MODERATOR_DOCUMENT_TYPE_NAME, ELECTED_CHARTER_DOCUMENT_TYPE_NAME,
property_names, ElectedCharter, ModerationCharterRewardSplit, SubmittedCharter,
ADDED_MODERATOR_DOCUMENT_TYPE_NAME, ELECTED_CHARTER_DOCUMENT_TYPE_NAME,
JOIN_REQUEST_DOCUMENT_TYPE_NAME, MODERATION_CHARTERS_CONTRACT_ID,
REASON_DOCUMENT_TYPE_NAME, REMOVED_MODERATOR_DOCUMENT_TYPE_NAME,
RESIGNATION_REQUEST_DOCUMENT_TYPE_NAME, SUBMITTED_CHARTER_DOCUMENT_TYPE_NAME,
Expand Down Expand Up @@ -711,10 +711,9 @@ mod moderation_charters_tests {
vec![],
"the encoded proposal passes the schema"
);
let read = validate_submitted_charter(document.properties(), PlatformVersion::latest())
.expect("validation executes")
let read = SubmittedCharter::from_document_properties(document.properties())
.into_data()
.expect("the proposal is valid");
.expect("the proposal reads");
assert_eq!(read, proposal);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ pub struct DataContractValidationVersions {
/// version 14: version 1 distribution rules and once-per-identity claims are rejected as
/// unsupported, matching older software that can not decode them.
pub validate_once_per_identity_distribution: OptionalFeatureVersion,
/// `ModerationCharter::validate`, the pure-data rules of a moderation charter. `None` below
/// protocol version 14, where the moderation charters system contract does not exist.
pub validate_moderation_charter: OptionalFeatureVersion,
}

#[derive(Clone, Debug, Default)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ pub const DPP_VALIDATION_VERSIONS_V1: DPPValidationVersions = DPPValidationVersi
validate_token_config_groups_exist: 0,
validate_localizations: 0,
validate_once_per_identity_distribution: None,
validate_moderation_charter: None,
},
document_type: DocumentTypeValidationVersions {
validate_update: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ pub const DPP_VALIDATION_VERSIONS_V2: DPPValidationVersions = DPPValidationVersi
validate_token_config_groups_exist: 0,
validate_localizations: 0,
validate_once_per_identity_distribution: None,
validate_moderation_charter: None,
},
document_type: DocumentTypeValidationVersions {
validate_update: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub const DPP_VALIDATION_VERSIONS_V3: DPPValidationVersions = DPPValidationVersi
validate_token_config_groups_exist: 0,
validate_localizations: 0,
validate_once_per_identity_distribution: None,
validate_moderation_charter: None,
},
document_type: DocumentTypeValidationVersions {
validate_update: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ pub const DPP_VALIDATION_VERSIONS_V5: DPPValidationVersions = DPPValidationVersi
data_contract: DataContractValidationVersions {
validate_config_update: 2,
validate_once_per_identity_distribution: Some(0),
// Moderation charters: the charter system contract and the pure-data rules of a
// charter exist from this protocol version on.
validate_moderation_charter: Some(0),
..DPP_VALIDATION_VERSIONS_V4.data_contract
},
document_type: DocumentTypeValidationVersions {
Expand Down
15 changes: 7 additions & 8 deletions packages/rs-platform-version/src/version/v14.rs
Original file line number Diff line number Diff line change
Expand Up @@ -982,12 +982,10 @@ pub const PROTOCOL_VERSION_14: ProtocolVersion = 14;
/// with `"resolution": 1`, the masternode vote without a Lock choice of
/// item 23, so an elected charter create opens or joins the contest for
/// its target. `SYSTEM_DATA_CONTRACT_VERSIONS_V3` registers it
/// (`moderation_charters: 1`), and
/// `DPP_VALIDATION_VERSIONS_V5.validate_moderation_charter = Some(0)` turns
/// on reading a proposal (basic error 11000), which holds no rule of its
/// own: the reward split sums to 100 through the contract's
/// `propertyConstraints` rule (item 39), so 11001 is no longer produced,
/// and the description fits 4096 bytes through the schema's own `maxBytes`
/// (`moderation_charters: 1`). A proposal holds no rule beyond its schema:
/// the reward split sums to 100 through the contract's
/// `propertyConstraints` rule (item 39), so 11001 is never produced, and
/// the description fits 4096 bytes through the schema's own `maxBytes`
/// (item 38); every document validation checks both. Genesis registers it
/// on chains born at this version (`create_genesis_state` v1, behind the
/// app-connect branch), `transition_to_version_14` inserts it on upgrade,
Expand Down Expand Up @@ -1041,8 +1039,9 @@ pub const PROTOCOL_VERSION_14: ProtocolVersion = 14;
/// nothing stored. They are fixed when the document type is created: a
/// changed `propertyConstraints` is an incompatible schema change on
/// update. The moderation charters contract declares its first one: a
/// `submittedCharter`'s `rewardSplit` members add up to 100, which
/// `validate_submitted_charter` therefore no longer checks (11001).
/// `submittedCharter`'s `rewardSplit` members add up to 100, replacing the
/// charter-specific check, whose error 11001 keeps its place in
/// `BasicError` but is never produced.
///
/// 40. **Elected moderation teams moderate from their stored charter**: seating
/// writes nothing. Awarding the contest of item 37 writes the winning
Expand Down
Loading