Closed ignazio-bovo closed 2 years ago
Phenomenal work.
As I said in DM, it's not 💯 obvious we need all cases, but having very granular messaging channels will anyway open the door to mappings that are simpler and faster. It is very very important that whomever is using the relevant extrinsic understands exactly what the guarantees are, so they know what the query node has to check on top, so this documentation will be a great base to add to the handbook later also.
Any reason why the emitted event should contain origin
, when signature verification is a runtime responsibility?
Any reason why the emitted event should contain origin, when signature verification is a runtime responsibility? It should'nt, perhaps I missed that, but it should def. contain whatever actor id or actor type information exists.
Initially intended to be a personal reference, I thought to make a document that could serve also as object of discussion, since inputs from Atlas / QN teams can change / nullify all of this.
Background
If this Metaprotocol framework architecture is desired
Then the joystream runtime layer should just verify role authentication or verify that some information is present on-chain. This means that there should be a remark extrinsics whenever a layer of authentication is needed. This also implies that no differentiation (at runtime level) is made for example between a concilor remark in the council system and a concilor remark in the proposal system.
Notation
element
@ModuleInstance::StarageElement(index1, index2, ..)
:element
is located in module instanceModuleInstance
at storage elementStorageElement
which can be either a variable or a map with indices(index1, index2, ...)
specifiedvariable
=Variant(elem1, elem2, ..)
: variable is matched against enum variantVariant
which migth have optional tuple containing elementselem1, elem2,...
collection.contains(element)
: boolean info on whethercollection
(either aVec
or aBTreeSet
) actually containselement
Metaprotocol *-remark extrinsics list
Below there is a list of extrinsics with respective signature, event, authentication triple. Eventual comments are made right after
Working Group - Lead
lead_remark(origin, msg: Vec<u8>)
LeadRemarked(origin, msg)
LEAD_AUTH(origin)
Working Group - Worker
worker_remark(origin, worker_id: WorkerId, msg: Vec<u8>)
LeadRemarked(origin, msg)
WORKER_AUTH(origin, worker_id)
Content - Channel Owner
channel_owner_remark(origin, owner: ChannelOwner, channel_id: ChannelId, msg: Vec<u8>)
ChannelOwnerRemarked(origin, actor,channel_id, msg)
CHANNEL_OWNER_AUTH(origin, channel_id, owner)
Content - Channel Collaborator
channel_collaborator_remark(origin, collaborator_id: MemberId, channel_id: ChannelId, msg: Vec<u8>)
ChannelCollaboratorRemarked(origin, collaborator_id, channel_id, msg)
MEMBER_AUTH(origin, collaborator_id)
&&CONTENT_COLLABORATOR_AUTH(channel_id, collaborator_id)
Content - Channel Moderator
channel_moderator_remark(origin, moderator_id: MemberId, channel_id: ChannelId, msg: Vec<u8>)
ChannelModeratorRemarked(origin, moderator_id, channel_id, msg)
MEMBER_AUTH(origin, moderator_id)
&&CONTENT_MODERATOR_AUTH(channel_id, moderator_id)
Content - Member
content_member_remark(origin, member_id: MemberId, video_id: VideoId, msg: Vec<u8>)
ContentMember(origin, moderator_id, channel_id, msg)
MEMBER_AUTH(origin, member_id)
&& (video
@Content::VideoById(video_id)
exists)I felt that this is required since QN has no way to verify that
video_id
actually exists. An alternative is to simply remove this extrinsics and allow comment/reaction for any possiblevideo_id
valueContent - Curator Group Member
content_curator_group_remark(origin, curator_id: MemberId, curator_group_id: CuratorGroupId, msg: Vec<u8>)
CuratorGroupRemarked(origin, curator_id, channel_id, msg)
CURATOR_GROUP_AUTH(origin, curator_id, curator_group_id)
Content - NFT Owner
nft_owner_remark(origin, owner: NftOwner, video_id: VideoId, msg: Vec<u8>)
NFTOwnerRemarked(origin, collaborator_id, channel_id, msg)
NFT_OWNER_AUTH(video_id, owner)
&& ((owner
=Member(member_id)
&&MEMBER_AUTH(origin, member_id)
) || (owner
=ChannelOwner(owner, channel_id)
&&CHANNEL_OWNER_AUTH(origin, channel_id, owner)
))Storage - Operator
storage_operator_remark(origin, worker_id: WorkerId, storage_bucket_id: StorageBucketId, msg: Vec<u8>)
StorageOperatorRemarked(origin, worker_id, storage_bucket_id, msg)
STORAGE_OPERATOR_AUTH(bucket_id, operator_id)
&&WORKER_AUTH(origin, worker_id)
Distribution - Operator
distribution_operator_remark(origin, worker_id: WorkerId, distribution_bucket_id: DistributionBucketId, msg: Vec<u8>)
DistributionOperatorRemarked(origin, worker_id, distribution_bucket_id, msg)
DISTRIBUTION_OPERATOR_AUTH(bucket_id, operator_id)
&&WORKER_AUTH(origin, worker_id)
Membership - member
member_remark(origin, member_id: MemberId, msg: Vec<u8>)
MemberRemarked(origin, member_id, msg)
MEMBER_AUTH(origin, member_id)
Bounty - Contributor
contributor_remark(origin, bounty_id: BountyId, contributor: BountyActor, msg: Vec<u8>)
ContributorRemarked(origin, member_id, msg)
BOUNTY_ACTOR_AUTH(origin, contributor)
&&BOUNTY_CONTRIBUTOR_AUTH(bounty_id, contributor)
There might be no need for interaction between contributors however
Bounty - Creator
creator_remark(origin, bounty_creator: BountyActor, bounty_id: BountyId, msg: Vec<u8>)
CreatorRemarked(origin, member_id, msg)
BOUNTY_ACTOR_AUTH(origin, bounty_creator)
&&BOUNTY_CREATOR_AUTH(bounty_id, bounty_creator)
Bounty - Entrant
entrant_remark(origin, bounty_id: BountyId, entry_id: EntryId, entrant_id: MemberId, msg: Vec<u8>)
EntrantRemarked(origin, member_id, msg)
MEMBER_AUTH(origin, entrant_id)
&&BOUNTY_ENTRANT_AUTH(bounty_id, entry_id, entrant_id)
Bounty - Oracle
oracle_remark(origin, bounty_id: BountyId, bounty_actor: BountyActor, msg: Vec<u8>)
OracleRemarked(origin, member_id, msg)
BOUNTY_ACTOR_AUTH(origin, actor)
&&BOUNTY_ORACLE_AUTH(bounty_id, entry_id, entrant_id)
Council - Candidate
candidate_remark(origin, candidate_id: MemberId, msg: Vec<u8>)
CandidateRemarked(origin, candidate_id, msg)
MEMBER_AUTH(origin, candidate_id)
&&CANDIDATE_AUTH(candidate_id)
Council - Councilor
councilor_remark(origin, councilor_id: MemberId, msg: Vec<u8>)
CouncilorRemarked(origin, candidate_id, msg)
MEMBER_AUTH(origin, councilor_id)
&&COUNCILOR_AUTH(councilor_id)
Proposal - Proposer
proposer_remark(origin, proposer_id: MemberId, proposal_id: ProposalId, msg: Vec<u8>)
ProposerRemarked(origin, proposer_id, msg)
MEMBER_AUTH(origin, proposer_id)
&&PROPOSER_AUTH(proposal_id, proposer_id)
Authentication routines
ROOT_AUTH(origin)
:origin
signed byROOT
LEAD_AUTH(origin)
:origin
signed byaccount_id
&&working_group::<I>::WorkerById(working_group<I>::CurrentLead()).role_account_id``= =account_id
WORKER_AUTH(origin, worker_id)
:origin
signed byaccount_id
&&worker
atworking_group::<I>::WorkerById(worker_id)
exists &&worker.role_account``= =account_id
MEMBER_AUTH(origin, member_id)
:origin
signed byaccount_id
&&member
@pallet_membership::MembershipById(member_id)
&&member.controller_account``= =account_id
CONTENT_COLLABORATOR_AUTH(channel_id, member_id)
:channel
@Content::ChannelById(channel_id)
exists &&channel.collaborator_set.contains(member_id)
CONTENT_MODERATOR_AUTH(channel_id, member_id)
:channel
@Content::ChannelById(channel_id)
exists &&channel.moderator_set.contains(member_id)
CURATOR_GROUP_AUTH(origin, curator_id, curator_group_id)
:WORKER_AUTH(origin, curator_id)
&&curator_group
@Content::CuratorGroupById(curator_group)
exists &&group.curators.contains(curator_id)
CHANNEL_OWNER_AUTH(origin, channel_id, owner)
:channel
@Content::ChannelById(channel_id)
exists &&channel.owner``= =owner
&& ((owner
=Member(member_id)
&&MEMBER_AUTH(origin, member_id)
) || (owner
=CuratorGroup(curator_id, curator_group_id)
&&CURATOR_GROUP_AUTH(origin, curator_id, curator_group_id)
)NFT_OWNER_AUTH(nft_id, owner)
:video
@Content::VideoById(video_id)
&&video.nft_status``= =Some(nft_owner)
&&nft_owner``= =owner
STORAGE_OPERATOR_AUTH(bucket_id, operator_id)
:storage bucket
@Storage::StorageBucketById(storage_bucket_id)
exists &&storage_bucket.operator_status``= =Accepted(worker_id)
DISTRIBUTION_OPERATOR_AUTH(bucket_id, operator_id)
:distribution bucket
@Distribution::DistributionBucketByFamilyIdById(distribution_bucket_family_id, distribution_bucket_id)
exists &&distribution_bucket.operators.contains(worker_id)
BOUNTY_ACTOR_AUTH(origin, bounty_actor)
:bounty_actor``= =Member(member_id)
&&MEMBER_AUTH(origin, member_id)
||ROOT_AUTH(origin)
BOUNTY_CONTRIBUTOR_AUTH(bounty_id, contributor)
:contributor
@Bounty::BountyContributions(bounty_id, contributor))
existsBOUNTY_ENTRANT_AUTH(bounty_id, entry_id, entrant_id)
:entry
@Bounty::Entries(bounty_id, entry_id)
exists &&entry.member_id``= =entrant_id
&&entry.work_submitted
BOUNTY_ORACLE_AUTH(bounty_id, oracle_id)
:bounty
@Bounty::Bounties(bounty_id)
exists &&bounty.parameters.oracle``= =oracle_id
BOUNTY_CREATOR_AUTH(bounty_id, creator)
:bounty
@Bounty::Bounties(bounty_id)
exists &&bounty.parameters.creator``= =creator
CANDIDATE_AUTH(candidate_id)
:candidate
@Council::Candidates(candidate_id)
exists &&candidate.cycle_id``= =Council::AnnouncmentPeriodNr
COUNCILOR_AUTH(councilor_id)
:Council::CouncilMembers.contains(councilor_id)
PROPOSER_AUTH(proposal_id, proposer_id)
:proposal
@Proposal::Proposals(proposal_id)
exists &&proposal.creation_params.proposer_id``= =proposer_id
┆Issue is synchronized with this Asana task by Unito ┆Link To Task: https://app.asana.com/0/1201958687417145/1201958692456531