nips/100.md
2023-04-28 22:03:20 +00:00

7.9 KiB

NIP-100

Nostr Groups

draft optional author:DanConwayDev

groups managed by evolving sets of Administrators with verifiable histories.

Purpose

This enables trust-minimised verification that an account was a member of a group at a specific point of time, even when the Administrators of that group evolves over time.

Useful for authorisation in asynchronous distributed systems in scenarios where:

  1. provisional authorisation states can be acted upon
  2. these changes are medimum-to-low-frequency
  3. its acceptable that these changes may take hours to confirm

Group Events

Group Event Types:

Kind Description
xxx init_group Initialize group
xxx group_modification_proposal
xxx vote approve / reject
xxx group_modification
xxx attest provide the OpenTimestamps for a note and / or attest a note has been broadcast

Group State

The state of a group at a point in time is constructed from the init_group event and the subsequent chain of modificaitons actioned through proposal andgroup_modification events.

{

    "id": <id of init_group>,
    "members": [
        <member's pubkey>,
        [
            <id of init_group to nest>,
            [optional]"groupvote" (limits voting power to 1 vote for group)
        ],
        ...
    ],
    "chaintip": <id of last group_modification applied>
    "admin": <admin init_group note id> | null,
    [optional]"meta": {... mirrors set_metadata (NIP-01)},
    [optional]"broadcast-attesters": [
        <pubkey>
    ] | null,

}    

Making Modifications

Changes can be permissionlessly proposed using group_modification_proposal events.

Proposals or direct modifications can be actioned by an Administrator through group_modification events.

Modifications are treated as provisional until attestation is recieved.

Administrator Removal

The only modification that requires additional authorisation is the removal, or limiting of voting rights, of one or more Administrators who have held the role continuously for 7 day or more. This happens through voting. This modification requires either:

  1. their vote(s) cast in favor
  2. a super majority of potential votes
  3. a simple majority of potential votes if 10 days have elapsed and no votes have provabilty been cast against the proposal

The change is actioned through a group_modification event which references the proposal and sufficent votes.

The proposal is deemed rejected without a simple majority after 10 days or being action after 30 days.

These Administrators are suspended from submitting group_modifications for the duration of the vote if both:

  1. the proposal was authored by an Administrator
  2. proposed removals cover only a minority of Administrators

Their voting rights remain uneffected.

Definitions

Members: accounts listed directly in the Group State members array and Members of groups referenced there in.

Administrator: The Administrators of the group referenced the Group State admin property. If null, accounts listed directly in the Group State members array and Administrators of groups referenced there in.

Voter: Any account that has held the Administrator role continously for 10 days prior to the proposal timestamp or an account that has held that role within the last 10 days who has also held the role for at least 30 days.

Optional Attestation

To prevent the key of an (ex)Administrator broadcasting a competing chain of modifications that undermines the Group State, we must verify that each event has been broadcast before it is confirmed. This is achieved through:

  1. trustless proof-of-existance through OpenTimestamps (NIP-03 or attest note)
  2. attestation of publication by at least one trusted third-party (required only if broadcasted-event-attesters is not null)

If a chain split occurs, the chain containing the smallest Attestation Adjusted Timestamp is the only valid chain. This is defined as:

***TODO - insert formula relating m, b and p *** + (1 / pk)

m = <timestamp of modification event>
b = <timestamp embedded into the blockheader of the earliest valid OpenTimestamp formatted as unix timestamp in seconds.
p = smallest timestamp of attestation of publication event
pk = authors public key

Groups can be used without, or with infrequent, attestation with a reduced trust model.

Group Events

Event xxx init_group

content is stringified:

"members": [
  <member's pubkey>,
  [
    <id of init_group to nest>,
    [optional]"groupvote" (limits voting power to 1 vote for group)
  ],
  ...
],
"admin": <admin init_group event id> | null,
[optional]"meta": {... mirrors set_metadata (NIP-01)},
[optional]"broadcast-attesters": [
    <pubkey>
]

Event xxx group_modification_proposal

  "tags": [
    ["group", <id of init_group note>],
    ["parent", <id of the previous group_modification in the chain or init_group if first group_modification],
    ...
  ]

content:

[optional]"remove":[<position in array>,...],
[optional]"add":[<member's pubkey>,...],
[optional]"admin":<id of init_group note> | null,
[optional]"meta":{
    <key to be updated>: <new key value>
}
[optional]"broadcast-attesters": [
    <pubkey>,
    ...
] | null

This also acts as a vote for the proposal, if the author has voting rights.

Timestamp must be greater than that of it's parent.

Event xxx vote

  "tags": [
    ["group", <id of init_group note>],
    ["proposal", <id of group_modification_proposal],
  ]
  "content:"true" or "false"

Considered invalid by supported client if the author has no voting rights.

Timestamp must be greater than that of the referenced proposal.

Event xxx group_modification

tags:

  "tags": [
    ["group", <id of init_group note>],
    ["parent", <id of the previous group_modification in the chain or init_group if first group_modification],
    [optional]["proposal", <id of a group_modification_proposal being implemented],
    [optional]["vote", <id of vote>],
    [optional]["vote", <id of vote>],
    [optional]["proposal", <id of a second group_modification_proposal being implemented],
    [optional]["vote", <id of vote>],
    [optional]["vote", <id of vote>],
    ...
  ]

One or more group_modification_proposal's are considered implemented when first referenced in the proposal tag in combination with sufficent valid vote events referenced using the vote tag.

A group_modification event is considered a vote for a proposal if referenced alongside an otherwise sufficent number of votes.

proposals are implemented in the order that they appear in tags.

proposed changed are merged with current state before any changes in content are implemented.

  1. array index positions references adapted from the pre-proposal state to match the corresponding item in the.
  2. if a proposal contains an instruction to add/remove a member, but before it is implemented the member is added/removed by another group_modification event, this specific instruction is ignored. The member is not added an additional time (which could increase their voting powers).

content:


[optional]"remove":[<position in array>,...],
[optional]"add":[<member's pubkey>,...],
[optional]"meta":{
    <key to be updated>: <new key value>
}
[optional]"broadcast-attesters": [
    <pubkey>,
    ...
] | null

Changes in a proposal being implemented should not be listed in the content.

Members cannot be removed directly using this event if admin is null in the current Group State. This is because Members are also Administrators in that instance.

Timestamp must be greater than that of it's parent.

Event xxx attest

  "tags": [
    ["group", <id of init_group note>],
    ["e", <id of note to attest>],
  ],
  "content:"",
  [optional]"attested-ots": <base64-encoded OTS file data of attested note>