About Status Policies
What is a status policy?
Status policies are used to define which custom statuses a record can have as well as the required quorum to change to these statuses. They have schema status which defines a specific structure of policy rules contained in values of the policy.
POST /v2/policies
{
...,
data: {
handle: '...',
schema: 'status',
record: '<record>',
filter: { ... },
values: [ ... ]
}
}At root level, the status policy can have fields which limit the policy to specific records:
record- defines that policy is only for specific record type, optional, if not defined policy applies to all record typesfilter- record must match the filter in order for policy to be applied to it, optional, if not defined policy applies to all records
POST /v2/policies
{
...,
"data": {
"handle": "fintech-wallet-status",
"schema": "status",
"record": "wallet",
"filter": { "data.schema": "fintech" }
"values": [ ... ]
}]
}
}The principle open unless whitelisted which we follow in all kinds of ledger rules is valid here also. So if for a record whose status is to be changed there is not any matching status policy (by record and filter) then the operation will be accepted. Otherwise the operation needs to be explicitly granted by one of applicable policy rules.
Property filter represents standard ledger filtering concept where language used in filter expression is mongo-compatible. This concept is already used in: access rules and effects.
Statuses policies are exposed on the same endpoint as access policies with distinction that the schema property is equal to status while for access policies schema is access. Schema of the policy record defines the structure of values array in policy.
Constraining quorum for statuses
POST /v2/policies
{
...,
"data": {
"handle": "wallet-status",
"schema": "status",
"record": "wallet",
"values": [{
"quorum": [{
"public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
}]
}]
}
}In the above case, in order for status to be changed there must be a proof with custom.status made by a signer with public key WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE= as specified in the quorum field of a policy. Quorum is array of signer references which follows the same structure as the signer references in access rules and policies. For example record owner can also be referenced in policy by using "quorum": [{ "$record": "owner" }] .
If based on policies, the signer is not in quorum required to set a status, or if additional proofs are required by quorum list, there will be no error. Only side effect will be that proof with status will be stored in record proofs but record status will not be changed.
Except quorum, the rule in status policy has optional field status which makes a rule applicable only to specific status. The policy below will requires a proof from signer(public) AweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE= to change wallet status to "active". Setting other statuses to wallet will not be allowed unless there is another policy/rule which grants that explicitly.
POST /v2/policies
{
...,
"data": {
"handle": "wallet-active",
"schema": "status",
"record": "wallet",
"values": [{
"status": "active",
"quorum": [{
"public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
}]
}]
}
}By default the status in policy rule is string and in this form it represents equality. It can also be a valid mongo compatible sub-expression for matching single object field as shown below by using $in.
POST /v2/policies
{
...,
"data": {
"handle": "wallet-active-inactive",
"schema": "status",
"record": "wallet",
"values": [{
"status": { $in: ["active", "inactive"] },
"quorum": [{
"public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
}]
}]
}
}To define a quorum for removing a label from a record, there is special value null. The same value is used in proofs for requesting the status removal.
POST /v2/policies
{
...,
"data": {
"handle": "wallet-remove-status",
"schema": "status",
"record": "wallet",
"values": [{
"status": null,
"quorum": [{
"public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
}]
}]
}
}A rule can also allow combination of removing and setting specific statuses, for example: "status": { $in: ["active", "inactive", null] }
Status policies evaluation
When evaluating status policies for setting a status to record there can be multiple matching policies with multiple values and multiple signers in quorum. To easier understand how they are combined the following rules are applied top-down:
-
If there is at least one status policy which matches the record by
recordandfilterthen, in order to allow setting the status of record, at least one policy must be found which allows setting this specific status based on policy rules. If there are no matching policies, then setting of status is allowed to anyone. -
Policy can have multiple rules in
valuesfield and it is considered that the policy grants setting status to record if at least one rule is found which grants this for this specific status. Emptyvaluesarray grants nothing. -
Single rule can have
statusfield which when exists will make rule applicable only if the desired status matches. Ifstatusfield is omitted then the rule allows all statuses - according to quorum.If there is any policy which matches
record/filterfor a record but none of them explicitly allows setting specific status then the proof which is to be added is not valid and will be rejected. Proof will not be stored and error response will be returned to caller. Restrictive nature of fieldstatusin policy rule is opposite than fieldswallet, filterin policy. While setting specificwalletand/orfilterin the policy will narrow status restrictions only to records which matches them, setting the specificstatusin policy rule will narrow the set of acceptable statuses this rule can apply to. So interpretation that rule withstatus: 'active'implies thatquorumis required only for statusactiveis wrong. Correct interpretation is that this rule with itsquorumcan be used only to grant setting statusactive. -
Rule also has
quorumarray of signer references and it is used to determine when the status from the proof can be persisted to a record. Quorum step will be evaluated only after all previous steps are executed successfully and the specific status from proof is allowed. Status will be persisted to a record only when all signers referenced in quorum had signed the record with a proof which has the desired status incustom.status. Emptyquorumarray means that quorum is not required and will cause that status is persisted to record immediately.If a proof with
statuspasses steps 1.-4. but the key used in this proof is not in the quorum or if another key is required to fulfill the quorum then the proof will be stored successfully, error will not be returned to caller, but status will not be persisted to record until the quorum of the rule which allows this status is achieved. -
When taking existing proofs from a record to evaluate
quorumthere is special constraint that only last N signatures with same status are taken into consideration. This is required so that proofs used in past to set some status cannot be reused to set this status again in future. This rule is easy to demonstrate and remember with this example:~~activated activated deactivated deactivated~~ activated
When a record is modified, it may fall under a policy that it does not satisfy. For example, there could be a wallet status policy that requires a signature from a specific key, but only if the wallet record has a schema like fintech. In this scenario, someone could first create a wallet without a schema or with a schema such as bank, then set the status to active and afterward change the schema to fintech. As a result, the wallet status is now subject to the policy, but the status was set without enforcing this policy.