Browse Source

query node - council & referendum mappings VIII

ondratra 3 years ago
parent
commit
afe96e8240

+ 66 - 62
query-node/mappings/council.ts

@@ -1,5 +1,5 @@
 import { EventContext, StoreContext, DatabaseManager } from '@dzlzv/hydra-common'
 import { EventContext, StoreContext, DatabaseManager } from '@dzlzv/hydra-common'
-import { bytesToString, deserializeMetadata, genericEventFields } from './common'
+import { deserializeMetadata, genericEventFields } from './common'
 import BN from 'bn.js'
 import BN from 'bn.js'
 import { FindConditions } from 'typeorm'
 import { FindConditions } from 'typeorm'
 
 
@@ -35,7 +35,6 @@ import {
   ReferendumStageRevealingOptionResult,
   ReferendumStageRevealingOptionResult,
 
 
   // Council & referendum schema types
   // Council & referendum schema types
-  ElectionProblemNotEnoughCandidates,
   CouncilStageUpdate,
   CouncilStageUpdate,
   CouncilStageAnnouncing,
   CouncilStageAnnouncing,
   CouncilStage,
   CouncilStage,
@@ -54,6 +53,7 @@ import {
 } from 'query-node/dist/model'
 } from 'query-node/dist/model'
 import { Council, Referendum } from './generated/types'
 import { Council, Referendum } from './generated/types'
 import { CouncilCandidacyNoteMetadata } from '@joystream/metadata-protobuf'
 import { CouncilCandidacyNoteMetadata } from '@joystream/metadata-protobuf'
+import { isSet } from '@joystream/metadata-protobuf/utils'
 
 
 /////////////////// Common - Gets //////////////////////////////////////////////
 /////////////////// Common - Gets //////////////////////////////////////////////
 
 
@@ -200,25 +200,21 @@ async function updateCouncilStage(
   store: DatabaseManager,
   store: DatabaseManager,
   councilStage: typeof CouncilStage,
   councilStage: typeof CouncilStage,
   blockNumber: number,
   blockNumber: number,
-  electionProblem?: typeof ElectionProblem
+  electionProblem?: ElectionProblem
 ): Promise<void> {
 ): Promise<void> {
+  const electedCouncil = await getCurrentElectedCouncil(store, true)
+  if (!electedCouncil) {
+    return
+  }
+
   const councilStageUpdate = new CouncilStageUpdate({
   const councilStageUpdate = new CouncilStageUpdate({
     stage: councilStage,
     stage: councilStage,
     changedAt: new BN(blockNumber),
     changedAt: new BN(blockNumber),
-    electionProblem: electionProblem || new VariantNone(),
+    electionProblem,
+    electedCouncil,
   })
   })
 
 
   await store.save<CouncilStageUpdate>(councilStageUpdate)
   await store.save<CouncilStageUpdate>(councilStageUpdate)
-
-  // update council record
-  const electedCouncil = await getCurrentElectedCouncil(store, true)
-  if (!electedCouncil) {
-    return
-  }
-
-  // electedCouncil.updates.push(councilStageUpdate) // uncomment after solving https://github.com/Joystream/hydra/issues/462
-  electedCouncil.updates = (electedCouncil.updates || []).concat([councilStageUpdate])
-  await store.save<ElectedCouncil>(electedCouncil)
 }
 }
 
 
 /*
 /*
@@ -329,7 +325,7 @@ export async function council_NotEnoughCandidates({ event, store }: EventContext
   const stage = new CouncilStageAnnouncing()
   const stage = new CouncilStageAnnouncing()
   stage.candidatesCount = new BN(0)
   stage.candidatesCount = new BN(0)
 
 
-  await updateCouncilStage(store, stage, event.blockNumber, new ElectionProblemNotEnoughCandidates())
+  await updateCouncilStage(store, stage, event.blockNumber, ElectionProblem.NOT_ENOUGH_CANDIDATES)
 }
 }
 
 
 /*
 /*
@@ -360,21 +356,11 @@ export async function council_VotingPeriodStarted({ event, store }: EventContext
   The event is emitted when a member announces candidacy to the council.
   The event is emitted when a member announces candidacy to the council.
 */
 */
 export async function council_NewCandidate({ event, store }: EventContext & StoreContext): Promise<void> {
 export async function council_NewCandidate({ event, store }: EventContext & StoreContext): Promise<void> {
-  // common event processing
+  // common event processing - init
 
 
   const [memberId, stakingAccount, rewardAccount, balance] = new Council.NewCandidateEvent(event).params
   const [memberId, stakingAccount, rewardAccount, balance] = new Council.NewCandidateEvent(event).params
   const member = await getMembership(store, memberId.toString())
   const member = await getMembership(store, memberId.toString())
 
 
-  const newCandidateEvent = new NewCandidateEvent({
-    ...genericEventFields(event),
-    member,
-    stakingAccount: stakingAccount.toString(),
-    rewardAccount: rewardAccount.toString(),
-    balance,
-  })
-
-  await store.save<NewCandidateEvent>(newCandidateEvent)
-
   // specific event processing
   // specific event processing
 
 
   // increase candidate count in stage update record
   // increase candidate count in stage update record
@@ -408,24 +394,29 @@ export async function council_NewCandidate({ event, store }: EventContext & Stor
     noteMetadata,
     noteMetadata,
   })
   })
   await store.save<Candidate>(candidate)
   await store.save<Candidate>(candidate)
+
+  // common event processing - save
+
+  const newCandidateEvent = new NewCandidateEvent({
+    ...genericEventFields(event),
+    candidate,
+    stakingAccount: stakingAccount.toString(),
+    rewardAccount: rewardAccount.toString(),
+    balance,
+  })
+
+  await store.save<NewCandidateEvent>(newCandidateEvent)
 }
 }
 
 
 /*
 /*
   The event is emitted when the new council is elected. Sufficient members were elected and there is no other problem.
   The event is emitted when the new council is elected. Sufficient members were elected and there is no other problem.
 */
 */
 export async function council_NewCouncilElected({ event, store }: EventContext & StoreContext): Promise<void> {
 export async function council_NewCouncilElected({ event, store }: EventContext & StoreContext): Promise<void> {
-  // common event processing
+  // common event processing - init
 
 
   const [memberIds] = new Council.NewCouncilElectedEvent(event).params
   const [memberIds] = new Council.NewCouncilElectedEvent(event).params
   const members = await store.getMany(Membership, { where: { id: memberIds.map((item) => item.toString()) } })
   const members = await store.getMany(Membership, { where: { id: memberIds.map((item) => item.toString()) } })
 
 
-  const newCouncilElectedEvent = new NewCouncilElectedEvent({
-    ...genericEventFields(event),
-    electedMembers: members,
-  })
-
-  await store.save<NewCouncilElectedEvent>(newCouncilElectedEvent)
-
   // specific event processing
   // specific event processing
 
 
   // mark old council as resinged
   // mark old council as resinged
@@ -463,6 +454,15 @@ export async function council_NewCouncilElected({ event, store }: EventContext &
 
 
   // end the last election round and start new one
   // end the last election round and start new one
   await startNextElectionRound(store, electedCouncil, electionRound)
   await startNextElectionRound(store, electedCouncil, electionRound)
+
+  // common event processing - save
+
+  const newCouncilElectedEvent = new NewCouncilElectedEvent({
+    ...genericEventFields(event),
+    electedCouncil,
+  })
+
+  await store.save<NewCouncilElectedEvent>(newCouncilElectedEvent)
 }
 }
 
 
 /*
 /*
@@ -495,10 +495,11 @@ export async function council_CandidacyStakeRelease({ event, store }: EventConte
 
 
   const [memberId] = new Council.CandidacyStakeReleaseEvent(event).params
   const [memberId] = new Council.CandidacyStakeReleaseEvent(event).params
   const member = await getMembership(store, memberId.toString())
   const member = await getMembership(store, memberId.toString())
+  const candidate = await getCandidate(store, memberId.toString()) // get last member's candidacy record
 
 
   const candidacyStakeReleaseEvent = new CandidacyStakeReleaseEvent({
   const candidacyStakeReleaseEvent = new CandidacyStakeReleaseEvent({
     ...genericEventFields(event),
     ...genericEventFields(event),
-    member,
+    candidate,
   })
   })
 
 
   await store.save<CandidacyStakeReleaseEvent>(candidacyStakeReleaseEvent)
   await store.save<CandidacyStakeReleaseEvent>(candidacyStakeReleaseEvent)
@@ -506,7 +507,6 @@ export async function council_CandidacyStakeRelease({ event, store }: EventConte
   // specific event processing
   // specific event processing
 
 
   // update candidate info about stake lock
   // update candidate info about stake lock
-  const candidate = await getCandidate(store, memberId.toString()) // get last member's candidacy record
   candidate.stakeLocked = false
   candidate.stakeLocked = false
   await store.save<Candidate>(candidate)
   await store.save<Candidate>(candidate)
 }
 }
@@ -552,10 +552,15 @@ export async function council_CandidacyNoteSet({ event, store }: EventContext &
   // unpack note's metadata and save it to db
   // unpack note's metadata and save it to db
   const metadata = deserializeMetadata(CouncilCandidacyNoteMetadata, note)
   const metadata = deserializeMetadata(CouncilCandidacyNoteMetadata, note)
   const noteMetadata = candidate.noteMetadata
   const noteMetadata = candidate.noteMetadata
-  noteMetadata.header = metadata?.header || undefined
+  // `XXX || (null as any)` construct clears metadata if requested (see https://github.com/Joystream/hydra/issues/435)
+  noteMetadata.header = isSet(metadata?.header) ? metadata?.header || (null as any) : metadata?.header
   noteMetadata.bulletPoints = metadata?.bulletPoints || []
   noteMetadata.bulletPoints = metadata?.bulletPoints || []
-  noteMetadata.bannerImageUri = metadata?.bannerImageUri || undefined
-  noteMetadata.description = metadata?.description || undefined
+  noteMetadata.bannerImageUri = isSet(metadata?.bannerImageUri)
+    ? metadata?.bannerImageUri || (null as any)
+    : metadata?.bannerImageUri
+  noteMetadata.description = isSet(metadata?.description)
+    ? metadata?.description || (null as any)
+    : metadata?.description
   await store.save<CandidacyNoteMetadata>(noteMetadata)
   await store.save<CandidacyNoteMetadata>(noteMetadata)
 
 
   const candidacyNoteSetEvent = new CandidacyNoteSetEvent({
   const candidacyNoteSetEvent = new CandidacyNoteSetEvent({
@@ -781,7 +786,7 @@ export async function referendum_ReferendumFinished({ event, store }: EventConte
       (item, index) =>
       (item, index) =>
         new ReferendumStageRevealingOptionResult({
         new ReferendumStageRevealingOptionResult({
           votePower: item.vote_power,
           votePower: item.vote_power,
-          option: members[index],
+          option: members.find((tmpMember) => tmpMember.id.toString() == optionResultsRaw[index].option_id.toString()),
         })
         })
     ),
     ),
   })
   })
@@ -795,27 +800,17 @@ export async function referendum_ReferendumFinished({ event, store }: EventConte
   The event is emitted when a vote is casted in the council election.
   The event is emitted when a vote is casted in the council election.
 */
 */
 export async function referendum_VoteCast({ event, store }: EventContext & StoreContext): Promise<void> {
 export async function referendum_VoteCast({ event, store }: EventContext & StoreContext): Promise<void> {
-  // common event processing
+  // common event processing - init
 
 
   const [account, hash, stake] = new Referendum.VoteCastEvent(event).params
   const [account, hash, stake] = new Referendum.VoteCastEvent(event).params
   const votePower = calculateVotePower(account.toString(), stake)
   const votePower = calculateVotePower(account.toString(), stake)
-  const hashString = bytesToString(hash)
-
-  const voteCastEvent = new VoteCastEvent({
-    ...genericEventFields(event),
-    account: account.toString(),
-    hash: hashString,
-    votePower,
-  })
-
-  await store.save<VoteCastEvent>(voteCastEvent)
 
 
   // specific event processing
   // specific event processing
 
 
   const electionRound = await getCurrentElectionRound(store)
   const electionRound = await getCurrentElectionRound(store)
 
 
   const castVote = new CastVote({
   const castVote = new CastVote({
-    commitment: hashString,
+    commitment: hash.toString(),
     electionRound,
     electionRound,
     stake,
     stake,
     stakeLocked: true,
     stakeLocked: true,
@@ -823,26 +818,26 @@ export async function referendum_VoteCast({ event, store }: EventContext & Store
     votePower: votePower,
     votePower: votePower,
   })
   })
   await store.save<CastVote>(castVote)
   await store.save<CastVote>(castVote)
+
+  // common event processing - save
+
+  const voteCastEvent = new VoteCastEvent({
+    ...genericEventFields(event),
+    castVote,
+  })
+
+  await store.save<VoteCastEvent>(voteCastEvent)
 }
 }
 
 
 /*
 /*
   The event is emitted when a previously casted vote is revealed.
   The event is emitted when a previously casted vote is revealed.
 */
 */
 export async function referendum_VoteRevealed({ event, store }: EventContext & StoreContext): Promise<void> {
 export async function referendum_VoteRevealed({ event, store }: EventContext & StoreContext): Promise<void> {
-  // common event processing
+  // common event processing - init
 
 
   const [account, memberId, salt] = new Referendum.VoteRevealedEvent(event).params
   const [account, memberId, salt] = new Referendum.VoteRevealedEvent(event).params
   const member = await getMembership(store, memberId.toString())
   const member = await getMembership(store, memberId.toString())
 
 
-  const voteRevealedEvent = new VoteRevealedEvent({
-    ...genericEventFields(event),
-    account: account.toString(),
-    member: member,
-    salt: bytesToString(salt),
-  })
-
-  await store.save<VoteRevealedEvent>(voteRevealedEvent)
-
   // specific event processing
   // specific event processing
 
 
   // read vote info
   // read vote info
@@ -856,6 +851,15 @@ export async function referendum_VoteRevealed({ event, store }: EventContext & S
   const candidate = await getCandidate(store, memberId.toString(), electionRound)
   const candidate = await getCandidate(store, memberId.toString(), electionRound)
   candidate.votePower = candidate.votePower.add(castVote.votePower)
   candidate.votePower = candidate.votePower.add(castVote.votePower)
   await store.save<Candidate>(candidate)
   await store.save<Candidate>(candidate)
+
+  // common event processing - save
+
+  const voteRevealedEvent = new VoteRevealedEvent({
+    ...genericEventFields(event),
+    castVote,
+  })
+
+  await store.save<VoteRevealedEvent>(voteRevealedEvent)
 }
 }
 
 
 /*
 /*

+ 0 - 1
query-node/mappings/membership.ts

@@ -109,7 +109,6 @@ async function createNewMemberFromParams(
     councilMembers: [],
     councilMembers: [],
     referendumStageRevealingOptionResults: [],
     referendumStageRevealingOptionResults: [],
     votesRecieved: [],
     votesRecieved: [],
-    electedCouncilEvents: [],
   })
   })
 
 
   await store.save<MemberMetadata>(member.metadata)
   await store.save<MemberMetadata>(member.metadata)

+ 12 - 16
query-node/schemas/council.graphql

@@ -41,22 +41,11 @@ type CouncilStageIdle @variant {
 
 
 union CouncilStage = CouncilStageAnnouncing | CouncilStageElection | CouncilStageIdle | VariantNone
 union CouncilStage = CouncilStageAnnouncing | CouncilStageElection | CouncilStageIdle | VariantNone
 
 
-type ElectionProblemNotEnoughCandidates @variant {
-  # no properties
-
-  # TODO: remove me - variant needs to have at least 1 property now
-  dummy: Int
+enum ElectionProblem {
+  NOT_ENOUGH_CANDIDATES
+  NEW_COUNCIL_NOT_ELECTED
 }
 }
 
 
-type ElectionProblemNewCouncilNotElected @variant {
-  # no properties
-
-  # TODO: remove me - variant needs to have at least 1 property now
-  dummy: Int
-}
-
-union ElectionProblem = ElectionProblemNotEnoughCandidates | ElectionProblemNewCouncilNotElected | VariantNone
-
 type Candidate @entity {
 type Candidate @entity {
   "Account used for staking currency needed for the candidacy."
   "Account used for staking currency needed for the candidacy."
   stakingAccountId: String!
   stakingAccountId: String!
@@ -179,11 +168,16 @@ type ReferendumStageRevealingOptionResult @entity {
   referendumFinishedEvent: ReferendumFinishedEvent!
   referendumFinishedEvent: ReferendumFinishedEvent!
 }
 }
 
 
+# This section is not useful before referencing variant is solved.
+# See commented reference in ElectionRound, for example.
+# Uncomment after solving the issue or delete if it can't be solved or is not needed
+# in the future.
+#
 # TODO: this maybe needs to be @entity - so it's saved in db
 # TODO: this maybe needs to be @entity - so it's saved in db
-union ReferendumStage = ReferendumStageInactive | ReferendumStageVoting | ReferendumStageRevealing | VariantNone
+#union ReferendumStage = ReferendumStageInactive | ReferendumStageVoting | ReferendumStageRevealing | VariantNone
 
 
 type CastVote @entity {
 type CastVote @entity {
-  "Hashed vote that was casted before being revealed."
+  "Hashed vote that was casted before being revealed. Hex format."
   commitment: String!
   commitment: String!
 
 
   "Election round."
   "Election round."
@@ -258,6 +252,8 @@ type ElectionRound @entity {
   candidates: [Candidate!]! @derivedFrom(field: "electionRound")
   candidates: [Candidate!]! @derivedFrom(field: "electionRound")
 }
 }
 
 
+# Not yet sure if this will be needed by apps using query node.
+#
 #type Budget @entity {
 #type Budget @entity {
 #  "Block number at which the next rewards will be paid."
 #  "Block number at which the next rewards will be paid."
 #  nextRewardPaymentsAt: BigInt!
 #  nextRewardPaymentsAt: BigInt!

+ 10 - 22
query-node/schemas/councilEvents.graphql

@@ -86,8 +86,8 @@ type NewCandidateEvent implements Event @entity {
 
 
   ### SPECIFIC DATA ###
   ### SPECIFIC DATA ###
 
 
-  "Candidate's membership."
-  member: Membership!
+  "Related candidate."
+  candidate: Candidate!
 
 
   "Candidate's account used to stake currency."
   "Candidate's account used to stake currency."
   stakingAccount: String!
   stakingAccount: String!
@@ -119,8 +119,8 @@ type NewCouncilElectedEvent implements Event @entity {
 
 
   ### SPECIFIC DATA ###
   ### SPECIFIC DATA ###
 
 
-  "Candidates' memberships."
-  electedMembers: [Membership!]
+  "Newly elected council."
+  electedCouncil: ElectedCouncil!
 }
 }
 
 
 type NewCouncilNotElectedEvent implements Event @entity {
 type NewCouncilNotElectedEvent implements Event @entity {
@@ -164,8 +164,8 @@ type CandidacyStakeReleaseEvent implements Event @entity {
 
 
   ### SPECIFIC DATA ###
   ### SPECIFIC DATA ###
 
 
-  "Candidate's membership."
-  member: Membership!
+  "Related candidate."
+  candidate: Candidate!
 }
 }
 
 
 type CandidacyWithdrawEvent implements Event @entity {
 type CandidacyWithdrawEvent implements Event @entity {
@@ -513,14 +513,8 @@ type VoteCastEvent implements Event @entity {
 
 
   ### SPECIFIC DATA ###
   ### SPECIFIC DATA ###
 
 
-  "Account that cast the vote."
-  account: String!
-
-  "Hash of sealed vote."
-  hash: String!
-
-  "Vote power decided by amount staked."
-  votePower: BigInt!
+  "Vote cast."
+  castVote: CastVote!
 }
 }
 
 
 type VoteRevealedEvent implements Event @entity {
 type VoteRevealedEvent implements Event @entity {
@@ -543,14 +537,8 @@ type VoteRevealedEvent implements Event @entity {
 
 
   ### SPECIFIC DATA ###
   ### SPECIFIC DATA ###
 
 
-  "Account that cast a vote."
-  account: String!
-
-  "Membership of user that cast the vote."
-  member: Membership!
-
-  "Salt that has been used for the vote's hash creation."
-  salt: String!
+  "Vote cast."
+  castVote: CastVote!
 }
 }
 
 
 type StakeReleasedEvent implements Event @entity {
 type StakeReleasedEvent implements Event @entity {

+ 0 - 3
query-node/schemas/membership.graphql

@@ -97,9 +97,6 @@ type Membership @entity {
 
 
   "Votes recieved in referendums by this member."
   "Votes recieved in referendums by this member."
   votesRecieved: [CastVote!] @derivedFrom(field: "voteFor")
   votesRecieved: [CastVote!] @derivedFrom(field: "voteFor")
-
-  "Events announcing council being elected."
-  electedCouncilEvents: [NewCouncilElectedEvent!] @derivedFrom(field: "electedMembers")
 }
 }
 
 
 type MembershipSystemSnapshot @entity {
 type MembershipSystemSnapshot @entity {