Browse Source

Merge pull request #3283 from mnaamani/faucet-init-flow

Faucet init flow
Mokhtar Naamani 3 years ago
parent
commit
c043c6f92b

+ 2 - 0
start.sh

@@ -49,6 +49,8 @@ if [[ $SKIP_CHAIN_SETUP != 'true' ]]; then
   ./tests/integration-tests/run-test-scenario.sh ${INIT_CHAIN_SCENARIO}
 
   ## Member faucet
+  export SCREENING_AUTHORITY_SEED=$(cat ./tests/integration-tests/output.json | jq -r .faucet.suri)
+  export INVITING_MEMBER_ID=$(cat ./tests/integration-tests/output.json | jq -r .faucet.memberId)
   docker-compose up -d faucet
 
   ## Storage Infrastructure Nodes

+ 20 - 0
tests/integration-tests/src/Api.ts

@@ -69,6 +69,11 @@ import {
 } from './consts'
 import { CategoryId } from '@joystream/types/forum'
 
+export type FaucetInfo = {
+  suri: string
+  memberId: number
+}
+
 export type KeyGenInfo = {
   start: number
   final: number
@@ -101,6 +106,8 @@ export class ApiFactory {
   // source of funds for all new accounts
   private readonly treasuryAccount: string
 
+  public faucetInfo: FaucetInfo
+
   public static async create(
     provider: WsProvider,
     treasuryAccountUri: string,
@@ -141,6 +148,7 @@ export class ApiFactory {
     this.addressesToKeyId = new Map()
     this.addressesToSuri = new Map()
     this.keyId = 0
+    this.faucetInfo = { suri: '', memberId: 0 }
   }
 
   public getApi(label: string): Api {
@@ -197,6 +205,10 @@ export class ApiFactory {
     }
     return suri
   }
+
+  public setFaucetInfo(info: FaucetInfo): void {
+    this.faucetInfo = info
+  }
 }
 
 export class Api {
@@ -1069,4 +1081,12 @@ export class Api {
       params: details.event.data[3] as VideoCreationParameters,
     }
   }
+
+  public setFaucetInfo(info: FaucetInfo): void {
+    this.factory.setFaucetInfo(info)
+  }
+
+  public getFaucetInfo(): FaucetInfo {
+    return this.factory.faucetInfo
+  }
 }

+ 6 - 2
tests/integration-tests/src/Scenario.ts

@@ -1,5 +1,5 @@
 import { WsProvider } from '@polkadot/api'
-import { ApiFactory, Api, KeyGenInfo } from './Api'
+import { ApiFactory, Api, KeyGenInfo, FaucetInfo } from './Api'
 import { QueryNodeApi } from './QueryNodeApi'
 import { config } from 'dotenv'
 import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'
@@ -23,6 +23,7 @@ type TestsOutput = {
   accounts: { [k: string]: number }
   keyIds: KeyGenInfo
   miniSecret: string
+  faucet: FaucetInfo
 }
 
 function writeOutput(api: Api, miniSecret: string) {
@@ -33,10 +34,13 @@ function writeOutput(api: Api, miniSecret: string) {
   // first and last key id used to generate keys in this scenario
   const keyIds = api.keyGenInfo()
 
+  const faucet = api.getFaucetInfo()
+
   const output: TestsOutput = {
     accounts,
     keyIds,
     miniSecret,
+    faucet,
   }
 
   fs.writeFileSync(OUTPUT_FILE_PATH, JSON.stringify(output, undefined, 2))
@@ -44,7 +48,7 @@ function writeOutput(api: Api, miniSecret: string) {
 
 export async function scenario(label: string, scene: (props: ScenarioProps) => Promise<void>): Promise<void> {
   // Load env variables
-  config()
+  config({ path: './.env' })
   const env = process.env
 
   // Connect api to the chain

+ 49 - 0
tests/integration-tests/src/fixtures/workingGroups/SetLeaderInvitationQuotaFixture.ts

@@ -0,0 +1,49 @@
+import BN from 'bn.js'
+import { assert } from 'chai'
+import { Api } from '../../Api'
+import { QueryNodeApi } from '../../QueryNodeApi'
+import { EventDetails, WorkingGroupModuleName } from '../../types'
+import { BaseWorkingGroupFixture } from './BaseWorkingGroupFixture'
+import { SubmittableExtrinsic } from '@polkadot/api/types'
+import { ISubmittableResult } from '@polkadot/types/types/'
+import { Utils } from '../../utils'
+import {
+  ProposalFieldsFragment,
+  BudgetSetEventFieldsFragment,
+  WorkingGroupFieldsFragment,
+} from '../../graphql/generated/queries'
+
+export class SetLeaderInvitationQuotaFixture extends BaseWorkingGroupFixture {
+  protected group: WorkingGroupModuleName
+  protected quota: number
+
+  public constructor(api: Api, query: QueryNodeApi, group: WorkingGroupModuleName, quota: number) {
+    super(api, query, group)
+    this.group = group
+    this.quota = quota
+  }
+
+  protected async getSignerAccountOrAccounts(): Promise<string> {
+    return (await this.api.query.sudo.key()).toString()
+  }
+
+  protected async getExtrinsics(): Promise<SubmittableExtrinsic<'promise'>[]> {
+    const extrinsics = [this.api.tx.members.setLeaderInvitationQuota(this.quota)]
+    return extrinsics.map((tx) => this.api.tx.sudo.sudo(tx))
+  }
+
+  protected async getEventFromResult(result: ISubmittableResult): Promise<EventDetails> {
+    return await this.api.retrieveMembershipEventDetails(result, 'LeaderInvitationQuotaUpdated')
+  }
+
+  protected assertQueryNodeEventIsValid(qEvent: unknown, i: number): void {
+    // TODO: implement
+  }
+
+  async runQueryNodeChecks(): Promise<void> {
+    await super.runQueryNodeChecks()
+
+    // Query and check the events
+    // TODO: implement
+  }
+}

+ 57 - 0
tests/integration-tests/src/flows/faucet/initFaucet.ts

@@ -0,0 +1,57 @@
+import { FlowProps } from '../../Flow'
+import { extendDebug } from '../../Debugger'
+import { FixtureRunner } from '../../Fixture'
+import { BuyMembershipHappyCaseFixture, TransferInvitesHappyCaseFixture } from '../../fixtures/membership'
+import { SetBudgetFixture } from '../../fixtures/workingGroups/SetBudgetFixture'
+import { SetLeaderInvitationQuotaFixture } from '../../fixtures/workingGroups/SetLeaderInvitationQuotaFixture'
+import _ from 'lodash'
+import BN from 'bn.js'
+
+export default async function initFaucet({ api, env, query }: FlowProps): Promise<void> {
+  const debug = extendDebug('flow:initFaucet')
+  debug('Started')
+
+  const invitesToTransfer = 100
+  // Get membership working group leader
+  const membershipWorkingGroup = 'membershipWorkingGroup'
+  const [, membershipLeader] = await api.getLeader(membershipWorkingGroup)
+
+  // Grant lead invitation quota
+  const setLeaderInvitationQuotaFixture = new SetLeaderInvitationQuotaFixture(
+    api,
+    query,
+    membershipWorkingGroup,
+    invitesToTransfer + 10
+  )
+  await new FixtureRunner(setLeaderInvitationQuotaFixture).runWithQueryNodeChecks()
+
+  // The membership working group should have a budget allocated
+  const budgets: BN[] = [new BN(1000000)]
+  const setGroupBudgetFixture = new SetBudgetFixture(api, query, membershipWorkingGroup, budgets)
+  await new FixtureRunner(setGroupBudgetFixture).runWithQueryNodeChecks()
+
+  // Create a membership account for faucet
+  const faucetSuri = env.SCREENING_AUTHORITY_SEED || '//Faucet'
+  const faucetAccount = api.createCustomKeyPair(faucetSuri, true).address
+  const happyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, [faucetAccount])
+  await new FixtureRunner(happyCaseFixture).runWithQueryNodeChecks()
+  const [faucetMemberId] = happyCaseFixture.getCreatedMembers()
+
+  // Give the faucet member accounts some funds (they need some funds for extrinsics)
+  await api.treasuryTransferBalanceToAccounts([faucetAccount], new BN(200))
+
+  // Send lead invites to faucet member account
+  const [leadMemberControllerAccount] = await api.getMemberSigners([{ asMember: membershipLeader.member_id }])
+  const transferInvitesHappyCaseFixture = new TransferInvitesHappyCaseFixture(
+    api,
+    query,
+    { memberId: membershipLeader.member_id, account: leadMemberControllerAccount },
+    { memberId: faucetMemberId, account: faucetAccount },
+    invitesToTransfer
+  )
+  await new FixtureRunner(transferInvitesHappyCaseFixture).runWithQueryNodeChecks()
+
+  api.setFaucetInfo({ suri: faucetSuri, memberId: faucetMemberId.toNumber() })
+
+  debug('Done')
+}

+ 6 - 9
tests/integration-tests/src/scenarios/setupNewChain.ts

@@ -1,21 +1,18 @@
-import electCouncil from '../flows/council/elect'
 import leaderSetup from '../flows/working-groups/leadOpening'
 import updateAccountsFlow from '../misc/updateAllWorkerRoleAccountsFlow'
+import initFaucet from '../flows/faucet/initFaucet'
 import initStorage, { singleBucketConfig as defaultStorageConfig } from '../flows/storage/initStorage'
 import initDistribution, { singleBucketConfig as defaultDistributionConfig } from '../flows/storage/initDistribution'
 import { scenario } from '../Scenario'
 
 scenario('Setup new chain', async ({ job }) => {
-  job('Elect Council', electCouncil)
   const leads = job('Set WorkingGroup Leads', leaderSetup)
-  const updateWorkerAccounts = job('Update worker accounts', updateAccountsFlow).after(leads)
+  const updateAccounts = job('Update Worker Accounts', updateAccountsFlow).requires(leads)
+
+  job('Initialize Faucet', initFaucet).requires(updateAccounts)
 
   if (!process.env.SKIP_STORAGE_AND_DISTRIBUTION) {
-    job('initialize storage system', initStorage(defaultStorageConfig)).requires(updateWorkerAccounts)
-    job('initialize distribution system', initDistribution(defaultDistributionConfig)).requires(updateWorkerAccounts)
+    job('initialize storage system', initStorage(defaultStorageConfig)).requires(updateAccounts)
+    job('initialize distribution system', initDistribution(defaultDistributionConfig)).requires(updateAccounts)
   }
-
-  // TODO: Mock content
-  // assign members known accounts?
-  // assign council known accounts?
 })