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
7 changes: 4 additions & 3 deletions book/src/data-model/contract-moderation.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,16 @@ pub struct ElectedModerators {
pub join_window: u32, // seconds; 1 day to 4 weeks, 1 week by default
pub vote_window: u32, // the same
pub challenge_cool_down: u32, // seconds; 2 weeks to 3 years, always declared
pub election_delay: Option<u32>, // seconds after creation before the first charter; unbounded, none = at once
pub moderated_document_types: BTreeMap<DocumentName, BTreeSet<ModerationAbility>>, // per type: DeleteDocuments, Ban, Suspend, Warn
pub interim: InterimModerators, // ContractOwner, AppointedModerators(set), NotYetUsable, NoModeration
pub owner_protected: bool, // false by default
}
```

The declaration lives in `packages/rs-dpp/src/data_contract/config/moderation/elected.rs`. On the wire it is the third `$type` of the moderators, flat: `{"$type": "elected", "challengeCoolDown": 1209600, "moderatedDocumentTypes": {"post": ["ban", "deleteDocuments"]}, "interim": {"$type": "notYetUsable"}}`, with `joinWindow`, `voteWindow` and `ownerProtected` optional. Its parts:
The declaration lives in `packages/rs-dpp/src/data_contract/config/moderation/elected.rs`. On the wire it is the third `$type` of the moderators, flat: `{"$type": "elected", "challengeCoolDown": 1209600, "moderatedDocumentTypes": {"post": ["ban", "deleteDocuments"]}, "interim": {"$type": "notYetUsable"}}`, with `joinWindow`, `voteWindow`, `electionDelay` and `ownerProtected` optional. Its parts:

- **The election parameters** are fixed once set (`SystemLimits`: `min_contract_moderation_election_window_seconds` and `max_contract_moderation_election_window_seconds` bound both windows, `min_contract_moderation_challenge_cool_down_seconds` and `max_contract_moderation_challenge_cool_down_seconds` the cool-down). The join window is how long applicants may join an election once the first one applied, the vote window how long masternodes then vote, and the cool-down how long a seated team is safe from a challenge after a seat change. Nothing reads them yet.
- **The election parameters** are fixed once set (`SystemLimits`: `min_contract_moderation_election_window_seconds` and `max_contract_moderation_election_window_seconds` bound both windows, `min_contract_moderation_challenge_cool_down_seconds` and `max_contract_moderation_challenge_cool_down_seconds` the cool-down). The join window is how long applicants may join an election once the first one applied, the vote window how long masternodes then vote, and the cool-down how long a seated team is safe from a challenge after a seat change. Nothing reads them yet. The **election delay** is the one parameter the contract sets freely: how many seconds after its creation the first charter may be filed against it, the notice the contract gives before its first election can be called. It is optional and unbounded; left out, the election may be called at once. Because the declaration is made at the contract's creation and never changes, the creation is the declaration's own time. The charter contract's `targetContractId` reads it through the `moderation: "electionOpen"` requirement below.
- **The moderated set** is the document types the team moderates, each with the abilities a charter may claim on it: non-empty, each type a document type of the contract, each ability set non-empty and backed by the contract (`ban` needs the banlist, `suspend` the suspension list, `warn` the warning list, `deleteDocuments` the type itself flagged `canBeDeletedByModerators`, so deletions reach only flagged types, within their window). The charter of a team will say how those types are moderated, never which. The lists stay contract-wide: an ability on a type is what a team may do over the documents of that type. The set also bounds the interim block. A charter does not price the moderators part of an action: a type's own `actionFees.moderators` amount is the most a team may charge, a charter charges a share of it (the charter contract's business, not the declaration's), and the owner part stays what the type declares, immutable as before.
- **The interim** says who moderates until a team is seated. `ContractOwner` and `AppointedModerators(set)` are the merged kinds, with their authority, their limit and their existence check (41110 at create): they moderate, they are protected, and they are the team that claims the moderators pot. `NotYetUsable` names nobody: nobody moderates, nobody claims the pot (it accumulates for the team to come, `ContractFeeClaimNotAllowedError` for everyone), and the moderated document types can not be used. A contract that never attracts a team keeps those types unusable for good; the other types work as on an unmoderated contract. `NoModeration` names nobody too, with the moderated types usable meanwhile: nobody moderates and nobody claims the pot, and every type works as on an unmoderated contract until a team is seated.
- **The owner flag** says whether the contract owner is protected from the team once one is seated, as the owner and the moderators of the merged kinds are (41102 on a ban, a suspension or a deletion of its documents). Not protected by default. During the interim the owner is protected whenever it moderates, flag or not: `ContractModerationConfig::protects` is what the moderation transition checks, and it is `may_moderate` or the flag for the owner.
Expand All @@ -293,7 +294,7 @@ The declaration lives in `packages/rs-dpp/src/data_contract/config/moderation/el

**The interim block.** The batch transformer's `contract_moderation_gate` v0 runs it before the lists: on an elected contract whose interim is `NotYetUsable`, every document transition of a moderated document type, deletions included (nothing of those types was ever written), is refused, paid, with `ContractModeratedDocumentTypeNotYetUsableError` (41200) and its contract nonce bump, in a block and in the mempool. The lists are read only for the transitions on the other types, and not at all when nothing is left. The interim moderators of the other two kinds moderate through the same transition, the same gate and the same claim as the merged kinds; a moderation transition against a `NotYetUsable` contract fails as by a non-moderator (41101).

**Referencing an elected contract.** A document type that must point at a contract of this kind says so in its reference: `"refersTo": { "type": "contract", "contractRequirements": { "moderation": "elected" } }`. `contractRequirements` holds what the referenced contract must declare beyond existing, each key an aspect of the contract with a closed set of values or a bound: `moderation: "elected"`; `minimumAgeSeconds`, which requires the contract's recorded creation time to be at least that many seconds before the block time of the write (a delay between a contract's creation and the first charter against it, so a team cannot be seated before anyone has seen the contract); and `minimumSecondsSinceUpdate`, the same of the later of the contract's creation and last update times (so an old contract updated to declare elected moderation gets the same notice before its first charter; any update restarts the clock). A contract created before contracts recorded their creation time never meets either duration. Consensus checks them when the referring document is written, against the contract it has already fetched for the existence check and the block time, so they cost no further read; a contract that exists but does not meet a requirement refuses the write, paid, with `ReferencedContractRequirementNotMetError` (40135) naming the requirement, where a contract that does not exist is still 40120. A changed `contractRequirements` is an incompatible schema change on update, like the rest of a `refersTo`. The charter system contract's `targetContractId` is the first user.
**Referencing an elected contract.** A document type that must point at a contract of this kind says so in its reference: `"refersTo": { "type": "contract", "contractRequirements": { "moderation": "elected" } }`. `contractRequirements` holds what the referenced contract must declare beyond existing, each key an aspect of the contract with a closed set of values or a bound: `moderation: "elected"`, or `moderation: "electionOpen"`, which also requires the contract's own election delay to have passed since its creation, or the contract to declare none (the delay between a contract's creation and the first charter against it, so a team cannot be seated before anyone has seen the contract, set by each contract for itself). Both have a user in the charter contract: a charter proposal only needs the target to be `elected`, so teams can form during the notice, and the charter that opens the contest needs its election `electionOpen`; `minimumAgeSeconds`, a number of seconds the reference fixes, which requires the contract's recorded creation time to be at least that far before the block time of the write; and `minimumSecondsSinceUpdate`, the same of the later of the contract's creation and last update times (any update restarts the clock; an elected declaration can not be added by an update, so this one is for other uses than the charter). A contract created before contracts recorded their creation time never meets a duration, its own election delay included. Consensus checks them when the referring document is written, against the contract it has already fetched for the existence check and the block time, so they cost no further read; a contract that exists but does not meet a requirement refuses the write, paid, with `ReferencedContractRequirementNotMetError` (40135) naming the requirement, where a contract that does not exist is still 40120. A changed `contractRequirements` is an incompatible schema change on update, like the rest of a `refersTo`. The charter system contract's `targetContractId` is the first user.

**What comes next.** The charter system contract, applications and the election (new vote poll kinds), the seated team under the contract with its per-ability powers, charter-priced moderators amounts within the maximums, and challenges and amendments. Issue #4865 holds the design.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,13 @@
"pattern": "^[a-zA-Z0-9-_]{1,64}$"
},
"contractRequirements": {
"description": "contract references only: what the referenced contract must declare beyond existing, checked when the referring document is written against the contract already fetched for the existence check and the block time, so a requirement costs no further read. Each key names an aspect of the referenced contract and its value the requirement: moderation \"elected\" requires the contract to declare an elected moderation team; minimumAgeSeconds requires the contract's recorded creation time to be at least that many seconds before the block time of the write, and minimumSecondsSinceUpdate the later of its recorded creation and last update times (a contract without a recorded creation time never meets either). An unmet requirement refuses the write (ReferencedContractRequirementNotMetError, 40135)",
"description": "contract references only: what the referenced contract must declare beyond existing, checked when the referring document is written against the contract already fetched for the existence check and the block time, so a requirement costs no further read. Each key names an aspect of the referenced contract and its value the requirement: moderation \"elected\" requires the contract to declare an elected moderation team and \"electionOpen\" one whose own electionDelay, counted from the contract's creation, has passed at the block time of the write (or which declares none); minimumAgeSeconds requires the contract's recorded creation time to be at least that many seconds before the block time of the write, and minimumSecondsSinceUpdate the later of its recorded creation and last update times (a contract without a recorded creation time never meets either). An unmet requirement refuses the write (ReferencedContractRequirementNotMetError, 40135)",
"type": "object",
"properties": {
"moderation": {
"enum": [
"elected"
"elected",
"electionOpen"
]
},
"minimumAgeSeconds": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ mod tests {
BTreeSet::from([ModerationAbility::Ban]),
)]),
interim: InterimModerators::ContractOwner,
election_delay: None,
owner_protected: false,
};
modify(&mut declaration);
Expand All @@ -238,10 +239,11 @@ mod tests {
assert!(kept.is_valid(), "{:?}", kept.errors);

type Change = (&'static str, fn(&mut ElectedModerators));
let changes: [Change; 7] = [
let changes: [Change; 8] = [
("join window", |d| d.join_window += 1),
("vote window", |d| d.vote_window += 1),
("challenge cool-down", |d| d.challenge_cool_down += 1),
("election delay", |d| d.election_delay = Some(1)),
("moderated set", |d| {
d.moderated_document_types
.insert("like".to_string(), BTreeSet::from([ModerationAbility::Ban]));
Expand Down
Loading
Loading