Prechádzať zdrojové kódy

Integration tests: Initial update (key management, setupNewChain), fix start.sh script

Leszek Wiesner 3 rokov pred
rodič
commit
89fdd47491
44 zmenil súbory, kde vykonal 376 pridanie a 113 odobranie
  1. 3 5
      start.sh
  2. 5 0
      storage-playground-config.sh
  3. 2 0
      tests/integration-tests/.gitignore
  4. 158 27
      tests/integration-tests/src/Api.ts
  5. 2 0
      tests/integration-tests/src/Fixture.ts
  6. 1 1
      tests/integration-tests/src/QueryNodeApi.ts
  7. 65 8
      tests/integration-tests/src/Scenario.ts
  8. 28 12
      tests/integration-tests/src/consts.ts
  9. 17 12
      tests/integration-tests/src/fixtures/council/ElectCouncilFixture.ts
  10. 3 0
      tests/integration-tests/src/fixtures/council/NotEnoughCandidatesFixture.ts
  11. 4 1
      tests/integration-tests/src/fixtures/council/NotEnoughCandidatesWithVotesFixture.ts
  12. 2 2
      tests/integration-tests/src/fixtures/council/common.ts
  13. 1 1
      tests/integration-tests/src/fixtures/forum/InitializeForumFixture.ts
  14. 1 1
      tests/integration-tests/src/fixtures/proposals/AllProposalsOutcomesFixture.ts
  15. 1 1
      tests/integration-tests/src/fixtures/proposals/CreateProposalsFixture.ts
  16. 1 2
      tests/integration-tests/src/fixtures/workingGroups/DecreaseWorkerStakesFixture.ts
  17. 1 2
      tests/integration-tests/src/fixtures/workingGroups/FillOpeningsFixture.ts
  18. 3 3
      tests/integration-tests/src/fixtures/workingGroups/HireWorkersFixture.ts
  19. 1 2
      tests/integration-tests/src/fixtures/workingGroups/IncreaseWorkerStakesFixture.ts
  20. 1 2
      tests/integration-tests/src/fixtures/workingGroups/SlashWorkerStakesFixture.ts
  21. 1 2
      tests/integration-tests/src/fixtures/workingGroups/TerminateWorkersFixture.ts
  22. 2 2
      tests/integration-tests/src/flows/council/failToElect.ts
  23. 1 1
      tests/integration-tests/src/flows/forum/polls.ts
  24. 2 2
      tests/integration-tests/src/flows/membership/creatingMemberships.ts
  25. 2 2
      tests/integration-tests/src/flows/membership/invitingMembers.ts
  26. 2 2
      tests/integration-tests/src/flows/membership/managingStakingAccounts.ts
  27. 1 1
      tests/integration-tests/src/flows/membership/transferringInvites.ts
  28. 2 2
      tests/integration-tests/src/flows/membership/updatingAccounts.ts
  29. 1 1
      tests/integration-tests/src/flows/membership/updatingProfile.ts
  30. 1 1
      tests/integration-tests/src/flows/proposals/cancellingProposal.ts
  31. 1 1
      tests/integration-tests/src/flows/proposals/exactExecutionBlock.ts
  32. 1 1
      tests/integration-tests/src/flows/proposals/expireProposal.ts
  33. 2 2
      tests/integration-tests/src/flows/proposals/index.ts
  34. 1 1
      tests/integration-tests/src/flows/proposals/runtimeUpgradeProposal.ts
  35. 1 1
      tests/integration-tests/src/flows/proposals/vetoProposal.ts
  36. 1 1
      tests/integration-tests/src/flows/proposalsDiscussion/index.ts
  37. 1 1
      tests/integration-tests/src/flows/working-groups/groupBudget.ts
  38. 1 1
      tests/integration-tests/src/flows/working-groups/leadOpening.ts
  39. 3 3
      tests/integration-tests/src/flows/working-groups/openingsAndApplications.ts
  40. 2 2
      tests/integration-tests/src/flows/working-groups/workerActions.ts
  41. 15 0
      tests/integration-tests/src/misc/updateAllWorkerRoleAccountsFlow.ts
  42. 14 0
      tests/integration-tests/src/misc/updateWorkerAccountsFixture.ts
  43. 14 0
      tests/integration-tests/src/scenarios/setupNewChain.ts
  44. 4 1
      tests/integration-tests/src/types.ts

+ 3 - 5
start.sh

@@ -3,7 +3,7 @@ set -e
 
 # Run a complete joystream development network on your machine using docker
 
-INIT_CHAIN_SCENARIO=${INIT_CHAIN_SCENARIO:=setup-new-chain}
+INIT_CHAIN_SCENARIO=${INIT_CHAIN_SCENARIO:=setupNewChain}
 
 if [ "${PERSIST}" == true ]
 then
@@ -26,15 +26,13 @@ docker-compose up -d joystream-node
 
 ## Init the chain with some state
 export SKIP_MOCK_CONTENT=true
+export SKIP_QUERY_NODE_CHECKS=true
 # TODO: Move back to this approach once Giza<->Olympia integration tests merged
 # HOST_IP=$(tests/network-tests/get-host-ip.sh)
 # export COLOSSUS_1_URL="http://${HOST_IP}:3333"
 # export COLOSSUS_1_TRANSACTOR_KEY=$(docker run --rm --pull=always docker.io/parity/subkey:2.0.1 inspect ${COLOSSUS_1_TRANSACTOR_URI} --output-type json | jq .ss58Address -r)
 # export DISTRIBUTOR_1_URL="http://${HOST_IP}:3334"
-./tests/network-tests/run-test-scenario.sh ${INIT_CHAIN_SCENARIO}
-
-## Set sudo as the membership screening authority
-yarn workspace api-scripts set-sudo-as-screening-auth
+./tests/integration-tests/run-test-scenario.sh ${INIT_CHAIN_SCENARIO}
 
 ## Member faucet
 docker-compose up -d faucet

+ 5 - 0
storage-playground-config.sh

@@ -16,6 +16,11 @@ HOST_IP=$(tests/network-tests/get-host-ip.sh)
 ## Colossus 1
 CLI=storage-node/bin/run
 TRANSACTOR_KEY=$(docker run --rm --pull=always docker.io/parity/subkey:2.0.1 inspect ${COLOSSUS_1_TRANSACTOR_URI} --output-type json | jq .ss58Address -r)
+# Send some funds to TRANSACTOR to cover the acceptPendingDataObjects fees
+export AUTO_CONFIRM=true
+FUNDS_SOURCE_KEY=5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
+TRANSACTOR_INITIAL_BALANCE=100000
+yarn joystream-cli account:transferTokens --amount ${TRANSACTOR_INITIAL_BALANCE} --from ${FUNDS_SOURCE_KEY}  --to ${TRANSACTOR_KEY}
 
 ${CLI} leader:update-bag-limit -l 10 --accountUri ${COLOSSUS_1_WORKER_URI}
 ${CLI} leader:update-voucher-limits -o 10000 -s 1000000000000 --accountUri ${COLOSSUS_1_WORKER_URI}

+ 2 - 0
tests/integration-tests/.gitignore

@@ -0,0 +1,2 @@
+output.json
+data/

+ 158 - 27
tests/integration-tests/src/Api.ts

@@ -4,14 +4,13 @@ import { ISubmittableResult } from '@polkadot/types/types'
 import { KeyringPair } from '@polkadot/keyring/types'
 import { AccountId, MemberId, PostId, ThreadId } from '@joystream/types/common'
 
-import { AccountInfo, Balance, EventRecord, BlockNumber, BlockHash } from '@polkadot/types/interfaces'
+import { AccountInfo, Balance, EventRecord, BlockNumber, BlockHash, LockIdentifier } from '@polkadot/types/interfaces'
 import BN from 'bn.js'
 import { QueryableConsts, QueryableStorage, SubmittableExtrinsic, SubmittableExtrinsics } from '@polkadot/api/types'
 import { Sender, LogLevel } from './sender'
 import { Utils } from './utils'
 import { types } from '@joystream/types'
 
-import { v4 as uuid } from 'uuid'
 import { extendDebug } from './Debugger'
 import { DispatchError } from '@polkadot/types/interfaces/system'
 import {
@@ -46,19 +45,44 @@ import {
 import { DeriveAllSections } from '@polkadot/api/util/decorate'
 import { ExactDerive } from '@polkadot/api-derive'
 import { ProposalId, ProposalParameters } from '@joystream/types/proposals'
-import { BLOCKTIME, proposalTypeToProposalParamsKey } from './consts'
+import {
+  BLOCKTIME,
+  KNOWN_WORKER_ROLE_ACCOUNT_DEFAULT_BALANCE,
+  proposalTypeToProposalParamsKey,
+  workingGroupNameByModuleName,
+} from './consts'
 import { CategoryId } from '@joystream/types/forum'
 
+export type KeyGenInfo = {
+  start: number
+  final: number
+  custom: string[]
+}
+
 export class ApiFactory {
   private readonly api: ApiPromise
   private readonly keyring: Keyring
+  // number used as part of key derivation path
+  private keyId = 0
+  // stores names of the created custom keys
+  private customKeys: string[] = []
+  // mapping from account address to key id.
+  // To be able to re-derive keypair externally when mini-secret is known.
+  readonly addressesToKeyId: Map<string, number> = new Map()
+  // mapping from account address to suri.
+  // To be able to get the suri of a known key for the purpose of, for example, interacting with the CLIs
+  readonly addressesToSuri: Map<string, string>
+  // mini secret used in SURI key derivation path
+  private readonly miniSecret: string
+
   // source of funds for all new accounts
   private readonly treasuryAccount: string
 
   public static async create(
     provider: WsProvider,
     treasuryAccountUri: string,
-    sudoAccountUri: string
+    sudoAccountUri: string,
+    miniSecret: string
   ): Promise<ApiFactory> {
     const debug = extendDebug('api-factory')
     let connectAttempts = 0
@@ -66,16 +90,16 @@ export class ApiFactory {
       connectAttempts++
       debug(`Connecting to chain, attempt ${connectAttempts}..`)
       try {
-        const api = await ApiPromise.create({ provider, types })
+        const api = new ApiPromise({ provider, types })
 
         // Wait for api to be connected and ready
-        await api.isReady
+        await api.isReadyOrError
 
         // If a node was just started up it might take a few seconds to start producing blocks
         // Give it a few seconds to be ready.
         await Utils.wait(5000)
 
-        return new ApiFactory(api, treasuryAccountUri, sudoAccountUri)
+        return new ApiFactory(api, treasuryAccountUri, sudoAccountUri, miniSecret)
       } catch (err) {
         if (connectAttempts === 3) {
           throw new Error('Unable to connect to chain')
@@ -85,32 +109,83 @@ export class ApiFactory {
     }
   }
 
-  constructor(api: ApiPromise, treasuryAccountUri: string, sudoAccountUri: string) {
+  constructor(api: ApiPromise, treasuryAccountUri: string, sudoAccountUri: string, miniSecret: string) {
     this.api = api
     this.keyring = new Keyring({ type: 'sr25519' })
     this.treasuryAccount = this.keyring.addFromUri(treasuryAccountUri).address
     this.keyring.addFromUri(sudoAccountUri)
+    this.miniSecret = miniSecret
+    this.addressesToKeyId = new Map()
+    this.addressesToSuri = new Map()
+    this.keyId = 0
   }
 
   public getApi(label: string): Api {
-    return new Api(this.api, this.treasuryAccount, this.keyring, label)
+    return new Api(this, this.api, this.treasuryAccount, this.keyring, label)
+  }
+
+  public createKeyPairs(n: number): { key: KeyringPair; id: number }[] {
+    const keys: { key: KeyringPair; id: number }[] = []
+    for (let i = 0; i < n; i++) {
+      const id = this.keyId++
+      const key = this.createKeyPair(`${id}`)
+      keys.push({ key, id })
+      this.addressesToKeyId.set(key.address, id)
+    }
+    return keys
+  }
+
+  private createKeyPair(suriPath: string, isCustom = false): KeyringPair {
+    if (isCustom) {
+      this.customKeys.push(suriPath)
+    }
+    const uri = `${this.miniSecret}//testing//${suriPath}`
+    const pair = this.keyring.addFromUri(uri)
+    this.addressesToSuri.set(pair.address, uri)
+    return pair
+  }
+
+  public createCustomKeyPair(customPath: string): KeyringPair {
+    return this.createKeyPair(customPath, true)
+  }
+
+  public keyGenInfo(): KeyGenInfo {
+    const start = 0
+    const final = this.keyId
+    return {
+      start,
+      final,
+      custom: this.customKeys,
+    }
+  }
+
+  public getAllGeneratedAccounts(): { [k: string]: number } {
+    return Object.fromEntries(this.addressesToKeyId)
+  }
+
+  public getKeypair(address: AccountId | string): KeyringPair {
+    return this.keyring.getPair(address)
   }
 
-  public close(): void {
-    this.api.disconnect()
+  public getSuri(address: AccountId | string): string {
+    const suri = this.addressesToSuri.get(address.toString())
+    if (!suri) {
+      throw new Error(`Suri for address ${address} not available!`)
+    }
+    return suri
   }
 }
 
 export class Api {
+  private readonly factory: ApiFactory
   private readonly api: ApiPromise
   private readonly sender: Sender
-  private readonly keyring: Keyring
   // source of funds for all new accounts
   private readonly treasuryAccount: string
 
-  constructor(api: ApiPromise, treasuryAccount: string, keyring: Keyring, label: string) {
+  constructor(factory: ApiFactory, api: ApiPromise, treasuryAccount: string, keyring: Keyring, label: string) {
+    this.factory = factory
     this.api = api
-    this.keyring = keyring
     this.treasuryAccount = treasuryAccount
     this.sender = new Sender(api, keyring, label)
   }
@@ -175,20 +250,24 @@ export class Api {
     this.sender.setLogLevel(LogLevel.Verbose)
   }
 
-  // Create new keys and store them in the shared keyring
-  public async createKeyPairs(n: number, withExistentialDeposit = true): Promise<KeyringPair[]> {
-    const nKeyPairs: KeyringPair[] = []
-    for (let i = 0; i < n; i++) {
-      // What are risks of generating duplicate keys this way?
-      // Why not use a deterministic /TestKeys/N and increment N
-      nKeyPairs.push(this.keyring.addFromUri(i + uuid().substring(0, 8)))
-    }
+  public async createKeyPairs(n: number, withExistentialDeposit = true): Promise<{ key: KeyringPair; id: number }[]> {
+    const pairs = this.factory.createKeyPairs(n)
     if (withExistentialDeposit) {
-      await Promise.all(
-        nKeyPairs.map(({ address }) => this.treasuryTransferBalance(address, this.existentialDeposit()))
-      )
+      await Promise.all(pairs.map(({ key }) => this.treasuryTransferBalance(key.address, this.existentialDeposit())))
     }
-    return nKeyPairs
+    return pairs
+  }
+
+  public createCustomKeyPair(path: string): KeyringPair {
+    return this.factory.createCustomKeyPair(path)
+  }
+
+  public keyGenInfo(): KeyGenInfo {
+    return this.factory.keyGenInfo()
+  }
+
+  public getAllGeneratedAccounts(): { [k: string]: number } {
+    return this.factory.getAllGeneratedAccounts()
   }
 
   public getBlockDuration(): BN {
@@ -220,7 +299,7 @@ export class Api {
     return accountData.data.free
   }
 
-  public async getStakedBalance(address: string | AccountId, lockId?: string): Promise<BN> {
+  public async getStakedBalance(address: string | AccountId, lockId?: LockIdentifier | string): Promise<BN> {
     const locks = await this.api.query.balances.locks(address)
     if (lockId) {
       const foundLock = locks.find((l) => l.id.eq(lockId))
@@ -426,6 +505,54 @@ export class Api {
     return await this.api.query[group].workerById(leadId.unwrap())
   }
 
+  public async getActiveWorkerIds(group: WorkingGroupModuleName): Promise<WorkerId[]> {
+    return (await this.api.query[group].workerById.entries<Worker>()).map(
+      ([
+        {
+          args: [id],
+        },
+      ]) => id
+    )
+  }
+
+  async assignWorkerRoleAccount(
+    group: WorkingGroupModuleName,
+    workerId: WorkerId,
+    account: string
+  ): Promise<ISubmittableResult> {
+    const worker = await this.api.query[group].workerById(workerId)
+    if (worker.isEmpty) {
+      throw new Error(`Worker not found by id: ${workerId}!`)
+    }
+
+    const memberController = await this.getControllerAccountOfMember(worker.member_id)
+    // there cannot be a worker associated with member that does not exist
+    if (!memberController) {
+      throw new Error('Member controller not found')
+    }
+
+    // Expect membercontroller key is already added to keyring
+    // Is is responsibility of caller to ensure this is the case!
+
+    const updateRoleAccountCall = this.api.tx[group].updateRoleAccount(workerId, account)
+    await this.prepareAccountsForFeeExpenses(memberController, [updateRoleAccountCall])
+    return this.sender.signAndSend(updateRoleAccountCall, memberController)
+  }
+
+  async assignWorkerWellknownAccount(
+    group: WorkingGroupModuleName,
+    workerId: WorkerId,
+    initialBalance = KNOWN_WORKER_ROLE_ACCOUNT_DEFAULT_BALANCE
+  ): Promise<ISubmittableResult[]> {
+    // path to append to base SURI
+    const uri = `worker//${workingGroupNameByModuleName[group]}//${workerId.toNumber()}`
+    const account = this.createCustomKeyPair(uri).address
+    return Promise.all([
+      this.assignWorkerRoleAccount(group, workerId, account),
+      this.treasuryTransferBalance(account, initialBalance),
+    ])
+  }
+
   public async getLeadRoleKey(group: WorkingGroupModuleName): Promise<string> {
     return (await this.getLeader(group)).role_account_id.toString()
   }
@@ -606,4 +733,8 @@ export class Api {
       postId: details.event.data[0] as PostId,
     }
   }
+
+  lockIdByGroup(group: WorkingGroupModuleName): LockIdentifier {
+    return this.api.consts[group].stakingHandlerLockId
+  }
 }

+ 2 - 0
tests/integration-tests/src/Fixture.ts

@@ -91,10 +91,12 @@ export abstract class BaseFixture {
 
 export abstract class BaseQueryNodeFixture extends BaseFixture {
   protected readonly query: QueryNodeApi
+  public readonly queryNodeChecksEnabled: boolean
 
   constructor(api: Api, query: QueryNodeApi) {
     super(api)
     this.query = query
+    this.queryNodeChecksEnabled = !process.env.SKIP_QUERY_NODE_CHECKS
   }
 
   public async runQueryNodeChecks(): Promise<void> {

+ 1 - 1
tests/integration-tests/src/QueryNodeApi.ts

@@ -346,7 +346,7 @@ export class QueryNodeApi {
       try {
         assertResultIsValid(result)
       } catch (e) {
-        debug(`Unexpected query result${e && e.message ? ` (${e.message})` : ''}`)
+        debug(`Unexpected query result${e instanceof Error ? ` (${e.message})` : ''}`)
         await retry(e)
         continue
       }

+ 65 - 8
tests/integration-tests/src/Scenario.ts

@@ -1,14 +1,15 @@
 import { WsProvider } from '@polkadot/api'
-import { ApiFactory } from './Api'
+import { ApiFactory, Api, KeyGenInfo } from './Api'
 import { QueryNodeApi } from './QueryNodeApi'
 import { config } from 'dotenv'
-import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client/core'
-import { extendDebug, Debugger } from './Debugger'
+import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'
+import { Debugger, extendDebug } from './Debugger'
 import { Flow } from './Flow'
 import { Job } from './Job'
 import { JobManager } from './JobManager'
 import { ResourceManager } from './Resources'
 import fetch from 'cross-fetch'
+import fs, { readFileSync } from 'fs'
 
 export type ScenarioProps = {
   env: NodeJS.ProcessEnv
@@ -16,6 +17,31 @@ export type ScenarioProps = {
   job: (label: string, flows: Flow[] | Flow) => Job
 }
 
+const OUTPUT_FILE_PATH = 'output.json'
+
+type TestsOutput = {
+  accounts: { [k: string]: number }
+  keyIds: KeyGenInfo
+  miniSecret: string
+}
+
+function writeOutput(api: Api, miniSecret: string) {
+  console.error('Writing generated account to', OUTPUT_FILE_PATH)
+  // account to key ids
+  const accounts = api.getAllGeneratedAccounts()
+
+  // first and last key id used to generate keys in this scenario
+  const keyIds = api.keyGenInfo()
+
+  const output: TestsOutput = {
+    accounts,
+    keyIds,
+    miniSecret,
+  }
+
+  fs.writeFileSync(OUTPUT_FILE_PATH, JSON.stringify(output, undefined, 2))
+}
+
 export async function scenario(scene: (props: ScenarioProps) => Promise<void>): Promise<void> {
   // Load env variables
   config()
@@ -24,18 +50,35 @@ export async function scenario(scene: (props: ScenarioProps) => Promise<void>):
   // Connect api to the chain
   const nodeUrl: string = env.NODE_URL || 'ws://127.0.0.1:9944'
   const provider = new WsProvider(nodeUrl)
-
+  const miniSecret = env.SURI_MINI_SECRET || ''
   const apiFactory = await ApiFactory.create(
     provider,
     env.TREASURY_ACCOUNT_URI || '//Alice',
-    env.SUDO_ACCOUNT_URI || '//Alice'
+    env.SUDO_ACCOUNT_URI || '//Alice',
+    miniSecret
   )
 
+  const api = apiFactory.getApi('Key Generation')
+
+  // Generate all key ids based on REUSE_KEYS or START_KEY_ID (if provided)
+  const reuseKeys = Boolean(env.REUSE_KEYS)
+  let startKeyId: number
+  let customKeys: string[] = []
+  if (reuseKeys) {
+    const output = JSON.parse(readFileSync(OUTPUT_FILE_PATH).toString()) as TestsOutput
+    startKeyId = output.keyIds.final
+    customKeys = output.keyIds.custom
+  } else {
+    startKeyId = parseInt(env.START_KEY_ID || '0')
+  }
+
+  await api.createKeyPairs(startKeyId, false)
+  customKeys.forEach((k) => api.createCustomKeyPair(k))
+
   const queryNodeUrl: string = env.QUERY_NODE_URL || 'http://127.0.0.1:8081/graphql'
 
   const queryNodeProvider = new ApolloClient({
     link: new HttpLink({ uri: queryNodeUrl, fetch }),
-    // uri: queryNodeUrl,
     cache: new InMemoryCache(),
     defaultOptions: { query: { fetchPolicy: 'no-cache', errorPolicy: 'all' } },
   })
@@ -50,14 +93,28 @@ export async function scenario(scene: (props: ScenarioProps) => Promise<void>):
 
   const resources = new ResourceManager()
 
+  process.on('SIGINT', () => {
+    console.error('Aborting scenario')
+    writeOutput(api, miniSecret)
+    process.exit(0)
+  })
+
+  let exitCode = 0
+
   try {
     await jobs.run(resources)
   } catch (err) {
     console.error(err)
-    process.exit(-1)
+    exitCode = -1
   }
 
+  writeOutput(api, miniSecret)
+
   // Note: disconnecting and then reconnecting to the chain in the same process
   // doesn't seem to work!
-  apiFactory.close()
+  // Disconnecting is causing error to be thrown:
+  // RPC-CORE: getStorage(key: StorageKey, at?: BlockHash): StorageData:: disconnected from ws://127.0.0.1:9944: 1000:: Normal connection closure
+  // Are there subsciptions somewhere?
+  // apiFactory.close()
+  process.exit(exitCode)
 }

+ 28 - 12
tests/integration-tests/src/consts.ts

@@ -9,6 +9,9 @@ export const validateType = <T>(obj: T) => obj
 // Test chain blocktime
 export const BLOCKTIME = 1000
 
+// Known worker role account default balance (JOY)
+export const KNOWN_WORKER_ROLE_ACCOUNT_DEFAULT_BALANCE = new BN(100000)
+
 export const MINIMUM_STAKING_ACCOUNT_BALANCE = 200
 export const MIN_APPLICATION_STAKE = new BN(2000)
 export const MIN_UNSTANKING_PERIOD = 43201
@@ -18,24 +21,31 @@ export const POST_DEPOSIT = new BN(10)
 export const PROPOSALS_POST_DEPOSIT = new BN(2000)
 export const ALL_BYTES = '0x' + Array.from({ length: 256 }, (v, i) => Buffer.from([i]).toString('hex')).join('')
 
-export const lockIdByWorkingGroup: { [K in WorkingGroupModuleName]: string } = {
-  storageWorkingGroup: '0x0606060606060606',
-  contentWorkingGroup: '0x0707070707070707',
-  forumWorkingGroup: '0x0808080808080808',
-  membershipWorkingGroup: '0x0909090909090909',
-  operationsWorkingGroup: '0x0d0d0d0d0d0d0d0d',
-  gatewayWorkingGroup: '0x0e0e0e0e0e0e0e0e',
-}
-
 export const workingGroups: WorkingGroupModuleName[] = [
   'storageWorkingGroup',
   'contentWorkingGroup',
   'forumWorkingGroup',
   'membershipWorkingGroup',
-  'operationsWorkingGroup',
+  'operationsWorkingGroupAlpha',
   'gatewayWorkingGroup',
+  'distributionWorkingGroup',
+  'operationsWorkingGroupBeta',
+  'operationsWorkingGroupGamma',
 ]
 
+export const workingGroupNameByModuleName = {
+  'storageWorkingGroup': 'Storage',
+  'contentWorkingGroup': 'Content',
+  'forumWorkingGroup': 'Forum',
+  'membershipWorkingGroup': 'Membership',
+  'operationsWorkingGroupAlpha': 'OperationsAlpha',
+  'gatewayWorkingGroup': 'Gateway',
+  'distributionWorkingGroup': 'Distribution',
+  'operationsWorkingGroupBeta': 'OperationsBeta',
+  'operationsWorkingGroupGamma': 'OperationsGamma',
+}
+validateType<{ [k in WorkingGroupModuleName]: string }>(workingGroupNameByModuleName)
+
 export function getWorkingGroupModuleName(group: WorkingGroup): WorkingGroupModuleName {
   if (group.isOfType('Content')) {
     return 'contentWorkingGroup'
@@ -45,10 +55,16 @@ export function getWorkingGroupModuleName(group: WorkingGroup): WorkingGroupModu
     return 'forumWorkingGroup'
   } else if (group.isOfType('Storage')) {
     return 'storageWorkingGroup'
-  } else if (group.isOfType('Operations')) {
-    return 'operationsWorkingGroup'
+  } else if (group.isOfType('OperationsAlpha')) {
+    return 'operationsWorkingGroupAlpha'
   } else if (group.isOfType('Gateway')) {
     return 'gatewayWorkingGroup'
+  } else if (group.isOfType('Distribution')) {
+    return 'distributionWorkingGroup'
+  } else if (group.isOfType('OperationsBeta')) {
+    return 'operationsWorkingGroupBeta'
+  } else if (group.isOfType('OperationsGamma')) {
+    return 'operationsWorkingGroupGamma'
   }
 
   throw new Error(`Unsupported working group: ${group}`)

+ 17 - 12
tests/integration-tests/src/fixtures/council/ElectCouncilFixture.ts

@@ -13,7 +13,7 @@ export class ElectCouncilFixture extends BaseQueryNodeFixture {
     const numberOfVoters = numberOfCandidates
 
     // Prepare memberships
-    const candidatesMemberAccounts = (await this.api.createKeyPairs(numberOfCandidates)).map((kp) => kp.address)
+    const candidatesMemberAccounts = (await this.api.createKeyPairs(numberOfCandidates)).map(({ key }) => key.address)
     const buyMembershipsFixture = new BuyMembershipHappyCaseFixture(api, query, candidatesMemberAccounts)
     await new FixtureRunner(buyMembershipsFixture).run()
     const candidatesMemberIds = buyMembershipsFixture.getCreatedMembers()
@@ -22,7 +22,7 @@ export class ElectCouncilFixture extends BaseQueryNodeFixture {
     const councilCandidateStake = api.consts.council.minCandidateStake
     const voteStake = api.consts.referendum.minimumStake
 
-    const candidatesStakingAccounts = (await this.api.createKeyPairs(numberOfCandidates)).map((kp) => kp.address)
+    const candidatesStakingAccounts = (await this.api.createKeyPairs(numberOfCandidates)).map(({ key }) => key.address)
     const addStakingAccountsFixture = new AddStakingAccountsHappyCaseFixture(
       api,
       query,
@@ -34,7 +34,7 @@ export class ElectCouncilFixture extends BaseQueryNodeFixture {
     )
     await new FixtureRunner(addStakingAccountsFixture).run()
 
-    const votersStakingAccounts = (await this.api.createKeyPairs(numberOfVoters)).map((kp) => kp.address)
+    const votersStakingAccounts = (await this.api.createKeyPairs(numberOfVoters)).map(({ key }) => key.address)
     await api.treasuryTransferBalanceToAccounts(votersStakingAccounts, voteStake.addn(MINIMUM_STAKING_ACCOUNT_BALANCE))
 
     // Announcing stage
@@ -80,15 +80,17 @@ export class ElectCouncilFixture extends BaseQueryNodeFixture {
     const candidatesToWinIds = candidatesMemberIds.slice(0, councilSize.toNumber()).map((id) => id.toString())
 
     // check intermediate election winners are properly set
-    await query.tryQueryWithTimeout(
-      () => query.getReferendumIntermediateWinners(cycleId.toNumber(), councilSize.toNumber()),
-      (qnReferendumIntermediateWinners) => {
-        assert.sameMembers(
-          qnReferendumIntermediateWinners.map((item) => item.member.id.toString()),
-          candidatesToWinIds
-        )
-      }
-    )
+    if (this.queryNodeChecksEnabled) {
+      await query.tryQueryWithTimeout(
+        () => query.getReferendumIntermediateWinners(cycleId.toNumber(), councilSize.toNumber()),
+        (qnReferendumIntermediateWinners) => {
+          assert.sameMembers(
+            qnReferendumIntermediateWinners.map((item) => item.member.id.toString()),
+            candidatesToWinIds
+          )
+        }
+      )
+    }
 
     await this.api.untilCouncilStage('Idle')
 
@@ -97,7 +99,10 @@ export class ElectCouncilFixture extends BaseQueryNodeFixture {
       councilMembers.map((m) => m.membership_id.toString()),
       candidatesToWinIds
     )
+  }
 
+  public async runQueryNodeChecks(): Promise<void> {
+    await super.runQueryNodeChecks()
     await assertCouncilMembersRuntimeQnMatch(this.api, this.query)
   }
 }

+ 3 - 0
tests/integration-tests/src/fixtures/council/NotEnoughCandidatesFixture.ts

@@ -51,7 +51,10 @@ export class NotEnoughCandidatesFixture extends BaseQueryNodeFixture {
       councilMemberIds.map((item) => item.toString()),
       councilMembersEnding.map((item) => item.membership_id.toString())
     )
+  }
 
+  public async runQueryNodeChecks(): Promise<void> {
+    await super.runQueryNodeChecks()
     await assertCouncilMembersRuntimeQnMatch(this.api, this.query)
   }
 }

+ 4 - 1
tests/integration-tests/src/fixtures/council/NotEnoughCandidatesWithVotesFixture.ts

@@ -20,7 +20,7 @@ export class NotEnoughCandidatesWithVotesFixture extends BaseQueryNodeFixture {
 
     // create voters
     const voteStake = this.api.consts.referendum.minimumStake
-    const votersStakingAccounts = (await this.api.createKeyPairs(numberOfVoters)).map((kp) => kp.address)
+    const votersStakingAccounts = (await this.api.createKeyPairs(numberOfVoters)).map(({ key }) => key.address)
     await this.api.treasuryTransferBalanceToAccounts(
       votersStakingAccounts,
       voteStake.addn(MINIMUM_STAKING_ACCOUNT_BALANCE)
@@ -76,7 +76,10 @@ export class NotEnoughCandidatesWithVotesFixture extends BaseQueryNodeFixture {
       councilMemberIds.map((item) => item.toString()),
       councilMembersEnding.map((item) => item.membership_id.toString())
     )
+  }
 
+  public async runQueryNodeChecks(): Promise<void> {
+    await super.runQueryNodeChecks()
     await assertCouncilMembersRuntimeQnMatch(this.api, this.query)
   }
 }

+ 2 - 2
tests/integration-tests/src/fixtures/council/common.ts

@@ -33,7 +33,7 @@ export async function prepareFailToElectResources(api: Api, query: QueryNodeApi)
   const numberOfCandidates = councilSize.add(minNumberOfExtraCandidates).toNumber()
 
   // prepare memberships
-  const candidatesMemberAccounts = (await api.createKeyPairs(numberOfCandidates)).map((kp) => kp.address)
+  const candidatesMemberAccounts = (await api.createKeyPairs(numberOfCandidates)).map(({ key }) => key.address)
   const buyMembershipsFixture = new BuyMembershipHappyCaseFixture(api, query, candidatesMemberAccounts)
   await new FixtureRunner(buyMembershipsFixture).run()
   const candidatesMemberIds = buyMembershipsFixture.getCreatedMembers()
@@ -41,7 +41,7 @@ export async function prepareFailToElectResources(api: Api, query: QueryNodeApi)
   // prepare staking accounts
   const councilCandidateStake = api.consts.council.minCandidateStake
 
-  const candidatesStakingAccounts = (await api.createKeyPairs(numberOfCandidates)).map((kp) => kp.address)
+  const candidatesStakingAccounts = (await api.createKeyPairs(numberOfCandidates)).map(({ key }) => key.address)
   const addStakingAccountsFixture = new AddStakingAccountsHappyCaseFixture(
     api,
     query,

+ 1 - 1
tests/integration-tests/src/fixtures/forum/InitializeForumFixture.ts

@@ -117,7 +117,7 @@ export class InitializeForumFixture extends BaseQueryNodeFixture {
       moderatorsPerCategory,
     } = this.config
     // Create forum members
-    const accounts = (await api.createKeyPairs(numberOfForumMembers)).map((kp) => kp.address)
+    const accounts = (await api.createKeyPairs(numberOfForumMembers)).map(({ key }) => key.address)
     const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, accounts)
     await new FixtureRunner(buyMembershipFixture).run()
     const forumMemberIds = buyMembershipFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/fixtures/proposals/AllProposalsOutcomesFixture.ts

@@ -54,7 +54,7 @@ export class AllProposalsOutcomesFixture extends BaseFixture {
       }
     }
 
-    const memberKeys = (await api.createKeyPairs(testCases.length)).map((key) => key.address)
+    const memberKeys = (await api.createKeyPairs(testCases.length)).map(({ key }) => key.address)
     const membersFixture = new BuyMembershipHappyCaseFixture(api, query, memberKeys)
     await new FixtureRunner(membersFixture).run()
     const memberIds = membersFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/fixtures/proposals/CreateProposalsFixture.ts

@@ -53,7 +53,7 @@ export class CreateProposalsFixture extends StandardizedFixture {
 
   protected async initStakingAccounts(): Promise<void> {
     const { api, query } = this
-    const stakingAccounts = (await this.api.createKeyPairs(this.proposalsParams.length)).map((kp) => kp.address)
+    const stakingAccounts = (await this.api.createKeyPairs(this.proposalsParams.length)).map(({ key }) => key.address)
     const addStakingAccountsFixture = new AddStakingAccountsHappyCaseFixture(
       api,
       query,

+ 1 - 2
tests/integration-tests/src/fixtures/workingGroups/DecreaseWorkerStakesFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { lockIdByWorkingGroup } from '../../consts'
 import { StakeDecreasedEventFieldsFragment, WorkerFieldsFragment } from '../../graphql/generated/queries'
 
 export class DecreaseWorkerStakesFixture extends BaseWorkingGroupFixture {
@@ -36,7 +35,7 @@ export class DecreaseWorkerStakesFixture extends BaseWorkingGroupFixture {
   protected async loadWorkersData(): Promise<void> {
     this.workers = await this.api.query[this.group].workerById.multi<Worker>(this.workerIds)
     this.workerStakes = await Promise.all(
-      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, lockIdByWorkingGroup[this.group]))
+      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, this.api.lockIdByGroup(this.group)))
     )
   }
 

+ 1 - 2
tests/integration-tests/src/fixtures/workingGroups/FillOpeningsFixture.ts

@@ -10,7 +10,6 @@ import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
 import { BTreeSet } from '@polkadot/types'
 import { registry } from '@joystream/types'
-import { lockIdByWorkingGroup } from '../../consts'
 import {
   LeaderSetEventFieldsFragment,
   OpeningFieldsFragment,
@@ -80,7 +79,7 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
       this.acceptedApplicationsArrays.map((acceptedApplications) =>
         Promise.all(
           acceptedApplications.map((a) =>
-            this.api.getStakedBalance(a.staking_account_id, lockIdByWorkingGroup[this.group])
+            this.api.getStakedBalance(a.staking_account_id, this.api.lockIdByGroup(this.group))
           )
         )
       )

+ 3 - 3
tests/integration-tests/src/fixtures/workingGroups/HireWorkersFixture.ts

@@ -41,9 +41,9 @@ export class HireWorkersFixture extends BaseQueryNodeFixture {
     const { stake: openingStake, metadata: openingMetadata } = DEFAULT_OPENING_PARAMS
 
     // Create the applications
-    const roleAccounts = (await this.api.createKeyPairs(this.workersN)).map((kp) => kp.address)
-    const stakingAccounts = (await this.api.createKeyPairs(this.workersN)).map((kp) => kp.address)
-    const rewardAccounts = (await this.api.createKeyPairs(this.workersN)).map((kp) => kp.address)
+    const roleAccounts = (await this.api.createKeyPairs(this.workersN)).map(({ key }) => key.address)
+    const stakingAccounts = (await this.api.createKeyPairs(this.workersN)).map(({ key }) => key.address)
+    const rewardAccounts = (await this.api.createKeyPairs(this.workersN)).map(({ key }) => key.address)
 
     const buyMembershipFixture = new BuyMembershipHappyCaseFixture(this.api, this.query, roleAccounts)
     await new FixtureRunner(buyMembershipFixture).run()

+ 1 - 2
tests/integration-tests/src/fixtures/workingGroups/IncreaseWorkerStakesFixture.ts

@@ -8,7 +8,6 @@ import { WorkerId, Worker } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { lockIdByWorkingGroup } from '../../consts'
 import { StakeIncreasedEventFieldsFragment, WorkerFieldsFragment } from '../../graphql/generated/queries'
 
 export class IncreaseWorkerStakesFixture extends BaseWorkingGroupFixture {
@@ -33,7 +32,7 @@ export class IncreaseWorkerStakesFixture extends BaseWorkingGroupFixture {
   protected async loadWorkersData(): Promise<void> {
     this.workers = await this.api.query[this.group].workerById.multi<Worker>(this.workerIds)
     this.workerStakes = await Promise.all(
-      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, lockIdByWorkingGroup[this.group]))
+      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, this.api.lockIdByGroup(this.group)))
     )
   }
 

+ 1 - 2
tests/integration-tests/src/fixtures/workingGroups/SlashWorkerStakesFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { lockIdByWorkingGroup } from '../../consts'
 import { StakeSlashedEventFieldsFragment, WorkerFieldsFragment } from '../../graphql/generated/queries'
 
 export class SlashWorkerStakesFixture extends BaseWorkingGroupFixture {
@@ -36,7 +35,7 @@ export class SlashWorkerStakesFixture extends BaseWorkingGroupFixture {
   protected async loadWorkersData(): Promise<void> {
     this.workers = await this.api.query[this.group].workerById.multi<Worker>(this.workerIds)
     this.workerStakes = await Promise.all(
-      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, lockIdByWorkingGroup[this.group]))
+      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, this.api.lockIdByGroup(this.group)))
     )
   }
 

+ 1 - 2
tests/integration-tests/src/fixtures/workingGroups/TerminateWorkersFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { lockIdByWorkingGroup } from '../../consts'
 import {
   LeaderUnsetEventFieldsFragment,
   TerminatedLeaderEventFieldsFragment,
@@ -41,7 +40,7 @@ export class TerminateWorkersFixture extends BaseWorkingGroupFixture {
   protected async loadWorkersData(): Promise<void> {
     this.workers = await this.api.query[this.group].workerById.multi<Worker>(this.workerIds)
     this.workerStakes = await Promise.all(
-      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, lockIdByWorkingGroup[this.group]))
+      this.workers.map((w) => this.api.getStakedBalance(w.staking_account_id, this.api.lockIdByGroup(this.group)))
     )
   }
 

+ 2 - 2
tests/integration-tests/src/flows/council/failToElect.ts

@@ -11,10 +11,10 @@ export default async function failToElectCouncil({ api, query }: FlowProps): Pro
   api.enableDebugTxLogs()
 
   const notEnoughCandidatesFixture = new NotEnoughCandidatesFixture(api, query)
-  await new FixtureRunner(notEnoughCandidatesFixture).run()
+  await new FixtureRunner(notEnoughCandidatesFixture).runWithQueryNodeChecks()
 
   const notEnoughCandidatesWithVotesFixture = new NotEnoughCandidatesWithVotesFixture(api, query)
-  await new FixtureRunner(notEnoughCandidatesWithVotesFixture).run()
+  await new FixtureRunner(notEnoughCandidatesWithVotesFixture).runWithQueryNodeChecks()
 
   debug('Done')
 }

+ 1 - 1
tests/integration-tests/src/flows/forum/polls.ts

@@ -17,7 +17,7 @@ export default async function polls({ api, query }: FlowProps): Promise<void> {
   api.enableDebugTxLogs()
 
   // Create test member(s)
-  const accounts = (await api.createKeyPairs(5)).map((kp) => kp.address)
+  const accounts = (await api.createKeyPairs(5)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, accounts)
   await new FixtureRunner(buyMembershipFixture).run()
   const memberIds = buyMembershipFixture.getCreatedMembers()

+ 2 - 2
tests/integration-tests/src/flows/membership/creatingMemberships.ts

@@ -14,12 +14,12 @@ export default async function creatingMemberships({ api, query, env }: FlowProps
   assert(N > 0)
 
   // Assert membership can be bought if sufficient funds are available
-  const nAccounts = (await api.createKeyPairs(N)).map((key) => key.address)
+  const nAccounts = (await api.createKeyPairs(N)).map(({ key }) => key.address)
   const happyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, nAccounts)
   await new FixtureRunner(happyCaseFixture).runWithQueryNodeChecks()
 
   // Assert account can not buy the membership with insufficient funds
-  const aAccount = (await api.createKeyPairs(1))[0].address
+  const aAccount = (await api.createKeyPairs(1))[0].key.address
   const insufficientFundsFixture = new BuyMembershipWithInsufficienFundsFixture(api, aAccount)
   await new FixtureRunner(insufficientFundsFixture).run()
 

+ 2 - 2
tests/integration-tests/src/flows/membership/invitingMembers.ts

@@ -13,12 +13,12 @@ export default async function invitingMembers({ api, query, env }: FlowProps): P
   const N: number = +env.MEMBERS_INVITE_N!
   assert(N > 0)
 
-  const [inviterAcc] = (await api.createKeyPairs(1)).map((key) => key.address)
+  const [inviterAcc] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipHappyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, [inviterAcc])
   await new FixtureRunner(buyMembershipHappyCaseFixture).run()
   const [inviterMemberId] = buyMembershipHappyCaseFixture.getCreatedMembers()
 
-  const inviteesAccs = (await api.createKeyPairs(N)).map((key) => key.address)
+  const inviteesAccs = (await api.createKeyPairs(N)).map(({ key }) => key.address)
   const inviteMembersHappyCaseFixture = new InviteMembersHappyCaseFixture(
     api,
     query,

+ 2 - 2
tests/integration-tests/src/flows/membership/managingStakingAccounts.ts

@@ -14,7 +14,7 @@ export default async function managingStakingAccounts({ api, query, env }: FlowP
   debug('Started')
   api.enableDebugTxLogs()
 
-  const [account] = (await api.createKeyPairs(1)).map((key) => key.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipHappyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipHappyCaseFixture).run()
   const [memberId] = buyMembershipHappyCaseFixture.getCreatedMembers()
@@ -22,7 +22,7 @@ export default async function managingStakingAccounts({ api, query, env }: FlowP
   const N: number = +env.STAKING_ACCOUNTS_ADD_N!
   assert(N > 0)
 
-  const stakingAccounts = (await api.createKeyPairs(N)).map((k) => k.address)
+  const stakingAccounts = (await api.createKeyPairs(N)).map(({ key }) => key.address)
   const addStakingAccountsHappyCaseFixture = new AddStakingAccountsHappyCaseFixture(
     api,
     query,

+ 1 - 1
tests/integration-tests/src/flows/membership/transferringInvites.ts

@@ -9,7 +9,7 @@ export default async function transferringInvites({ api, query, env }: FlowProps
   debug('Started')
   api.enableDebugTxLogs()
 
-  const [fromAcc, toAcc] = (await api.createKeyPairs(2)).map((key) => key.address)
+  const [fromAcc, toAcc] = (await api.createKeyPairs(2)).map(({ key }) => key.address)
   const buyMembershipHappyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, [fromAcc, toAcc])
   await new FixtureRunner(buyMembershipHappyCaseFixture).run()
   const [fromMemberId, toMemberId] = buyMembershipHappyCaseFixture.getCreatedMembers()

+ 2 - 2
tests/integration-tests/src/flows/membership/updatingAccounts.ts

@@ -9,11 +9,11 @@ export default async function updatingAccounts({ api, query }: FlowProps): Promi
   debug('Started')
   api.enableDebugTxLogs()
 
-  const [account] = (await api.createKeyPairs(1)).map((key) => key.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipHappyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipHappyCaseFixture).run()
   const [memberId] = buyMembershipHappyCaseFixture.getCreatedMembers()
-  const [newRootAccount, newControllerAccount] = (await api.createKeyPairs(2)).map((key) => key.address)
+  const [newRootAccount, newControllerAccount] = (await api.createKeyPairs(2)).map(({ key }) => key.address)
   const updateAccountsHappyCaseFixture = new UpdateAccountsHappyCaseFixture(
     api,
     query,

+ 1 - 1
tests/integration-tests/src/flows/membership/updatingProfile.ts

@@ -25,7 +25,7 @@ export default async function updatingProfile({ api, query }: FlowProps): Promis
     { handle: 'Updated handle', name: 'Updated name', about: 'Updated about' },
   ]
 
-  const [account] = (await api.createKeyPairs(1)).map((key) => key.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipHappyCaseFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipHappyCaseFixture).run()
   const [memberId] = buyMembershipHappyCaseFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/flows/proposals/cancellingProposal.ts

@@ -12,7 +12,7 @@ export default async function cancellingProposals({ api, query, lock }: FlowProp
 
   const unlock = await lock(Resource.Proposals)
 
-  const [account] = (await api.createKeyPairs(1)).map((kp) => kp.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipFixture).run()
   const [memberId] = buyMembershipFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/flows/proposals/exactExecutionBlock.ts

@@ -12,7 +12,7 @@ export default async function exactExecutionBlock({ api, query, lock }: FlowProp
 
   const unlock = await lock(Resource.Proposals)
 
-  const [account] = (await api.createKeyPairs(1)).map((kp) => kp.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipFixture).run()
   const [memberId] = buyMembershipFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/flows/proposals/expireProposal.ts

@@ -12,7 +12,7 @@ export default async function expireProposal({ api, query, lock }: FlowProps): P
 
   const unlock = await lock(Resource.Proposals)
 
-  const [account] = (await api.createKeyPairs(1)).map((kp) => kp.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipFixture).run()
   const [memberId] = buyMembershipFixture.getCreatedMembers()

+ 2 - 2
tests/integration-tests/src/flows/proposals/index.ts

@@ -27,7 +27,7 @@ export default async function creatingProposals({ api, query, lock }: FlowProps)
   await new FixtureRunner(createLeadOpeningsFixture).run()
   const [openingToCancelId, openingToFillId] = createLeadOpeningsFixture.getCreatedOpeningIds()
 
-  const [applicantControllerAcc, applicantStakingAcc] = (await api.createKeyPairs(2)).map((kp) => kp.address)
+  const [applicantControllerAcc, applicantStakingAcc] = (await api.createKeyPairs(2)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [applicantControllerAcc])
   await new FixtureRunner(buyMembershipFixture).run()
   const [applicantMemberId] = buyMembershipFixture.getCreatedMembers()
@@ -56,7 +56,7 @@ export default async function creatingProposals({ api, query, lock }: FlowProps)
   const [applicationId] = applyOnOpeningFixture.getCreatedApplicationsByOpeningId(openingToFillId)
   debug('Openings and applicantions created')
 
-  const accountsToFund = (await api.createKeyPairs(5)).map((key) => key.address)
+  const accountsToFund = (await api.createKeyPairs(5)).map(({ key }) => key.address)
   const proposalsToTest: TestedProposal[] = [
     { details: { AmendConstitution: 'New constitution' } },
     {

+ 1 - 1
tests/integration-tests/src/flows/proposals/runtimeUpgradeProposal.ts

@@ -28,7 +28,7 @@ export default async function runtimeUpgradeProposal({ api, query, lock, env }:
   )
 
   // Proposals to be "CancelledByRuntime"
-  const [memberAcc] = (await api.createKeyPairs(1)).map((kp) => kp.address)
+  const [memberAcc] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [memberAcc])
   await new FixtureRunner(buyMembershipFixture).run()
   const [memberId] = buyMembershipFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/flows/proposals/vetoProposal.ts

@@ -12,7 +12,7 @@ export default async function vetoProposal({ api, query, lock }: FlowProps): Pro
 
   const unlocks = await Promise.all(Array.from({ length: 2 }, () => lock(Resource.Proposals)))
 
-  const [account] = (await api.createKeyPairs(1)).map((kp) => kp.address)
+  const [account] = (await api.createKeyPairs(1)).map(({ key }) => key.address)
   const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [account])
   await new FixtureRunner(buyMembershipFixture).run()
   const [memberId] = buyMembershipFixture.getCreatedMembers()

+ 1 - 1
tests/integration-tests/src/flows/proposalsDiscussion/index.ts

@@ -23,7 +23,7 @@ export default async function proposalsDiscussion({ api, query, lock }: FlowProp
   api.enableDebugTxLogs()
 
   const threadsN = 3
-  const accounts = (await api.createKeyPairs(threadsN)).map((kp) => kp.address)
+  const accounts = (await api.createKeyPairs(threadsN)).map(({ key }) => key.address)
 
   const buyMembershipsFixture = new BuyMembershipHappyCaseFixture(api, query, accounts)
   await new FixtureRunner(buyMembershipsFixture).run()

+ 1 - 1
tests/integration-tests/src/flows/working-groups/groupBudget.ts

@@ -18,7 +18,7 @@ export default async function groupBudget({ api, query }: FlowProps): Promise<vo
       const setGroupBudgetFixture = new SetBudgetFixture(api, query, group, budgets)
       await new FixtureRunner(setGroupBudgetFixture).runWithQueryNodeChecks()
 
-      const recievers = (await api.createKeyPairs(5)).map((kp) => kp.address)
+      const recievers = (await api.createKeyPairs(5)).map(({ key }) => key.address)
       const amounts = recievers.map((reciever, i) => new BN(10000 * (i + 1)))
       const spendGroupBudgetFixture = new SpendBudgetFixture(api, query, group, recievers, amounts)
       await new FixtureRunner(spendGroupBudgetFixture).runWithQueryNodeChecks()

+ 1 - 1
tests/integration-tests/src/flows/working-groups/leadOpening.ts

@@ -25,7 +25,7 @@ export default async function leadOpening({ api, query, env }: FlowProps): Promi
       const [openingId] = createOpeningFixture.getCreatedOpeningIds()
       const { stake: openingStake, metadata: openingMetadata } = DEFAULT_OPENING_PARAMS
 
-      const [roleAccount, stakingAccount, rewardAccount] = (await api.createKeyPairs(3)).map((kp) => kp.address)
+      const [roleAccount, stakingAccount, rewardAccount] = (await api.createKeyPairs(3)).map(({ key }) => key.address)
       const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, [roleAccount])
       await new FixtureRunner(buyMembershipFixture).run()
       const [memberId] = buyMembershipFixture.getCreatedMembers()

+ 3 - 3
tests/integration-tests/src/flows/working-groups/openingsAndApplications.ts

@@ -85,9 +85,9 @@ export default async function openingsAndApplications({ api, query, env }: FlowP
       const { stake: openingStake, metadata: openingMetadata } = DEFAULT_OPENING_PARAMS
 
       // Create some applications
-      const roleAccounts = (await api.createKeyPairs(APPLICATION_CREATE_N)).map((kp) => kp.address)
-      const stakingAccounts = (await api.createKeyPairs(APPLICATION_CREATE_N)).map((kp) => kp.address)
-      const rewardAccounts = (await api.createKeyPairs(APPLICATION_CREATE_N)).map((kp) => kp.address)
+      const roleAccounts = (await api.createKeyPairs(APPLICATION_CREATE_N)).map(({ key }) => key.address)
+      const stakingAccounts = (await api.createKeyPairs(APPLICATION_CREATE_N)).map(({ key }) => key.address)
+      const rewardAccounts = (await api.createKeyPairs(APPLICATION_CREATE_N)).map(({ key }) => key.address)
 
       const buyMembershipFixture = new BuyMembershipHappyCaseFixture(api, query, roleAccounts)
       await new FixtureRunner(buyMembershipFixture).run()

+ 2 - 2
tests/integration-tests/src/flows/working-groups/workerActions.ts

@@ -36,7 +36,7 @@ export default async function workerActions({ api, query, env }: FlowProps): Pro
       // Independent updates that don't interfere with each other
       const workerUpdatesRunners: FixtureRunner[] = []
 
-      const newRoleAccounts = (await api.createKeyPairs(WORKERS_N)).map((kp) => kp.address)
+      const newRoleAccounts = (await api.createKeyPairs(WORKERS_N)).map(({ key }) => key.address)
       const updateRoleAccountsFixture = new UpdateWorkerRoleAccountsFixture(
         api,
         query,
@@ -48,7 +48,7 @@ export default async function workerActions({ api, query, env }: FlowProps): Pro
       await updateRoleAccountsRunner.run()
       workerUpdatesRunners.push(updateRoleAccountsRunner)
 
-      const newRewardAccounts = (await api.createKeyPairs(WORKERS_N)).map((kp) => kp.address)
+      const newRewardAccounts = (await api.createKeyPairs(WORKERS_N)).map(({ key }) => key.address)
       const updateRewardAccountsFixture = new UpdateWorkerRewardAccountsFixture(
         api,
         query,

+ 15 - 0
tests/integration-tests/src/misc/updateAllWorkerRoleAccountsFlow.ts

@@ -0,0 +1,15 @@
+import { UpdateWorkerAccountsFixture } from './updateWorkerAccountsFixture'
+
+import { FlowProps } from '../Flow'
+import { FixtureRunner } from '../Fixture'
+import { extendDebug } from '../Debugger'
+
+export default async function updateAllWorkerRoleAccounts({ api }: FlowProps): Promise<void> {
+  const debug = extendDebug('flow:updateAllWorkerRoleAccounts')
+  debug('Started')
+
+  const updateAccounts = new UpdateWorkerAccountsFixture(api)
+  await new FixtureRunner(updateAccounts).run()
+
+  debug('Done')
+}

+ 14 - 0
tests/integration-tests/src/misc/updateWorkerAccountsFixture.ts

@@ -0,0 +1,14 @@
+import { BaseFixture } from '../Fixture'
+import { workingGroups } from '../consts'
+
+export class UpdateWorkerAccountsFixture extends BaseFixture {
+  public async execute(): Promise<void> {
+    await Promise.all(
+      workingGroups.map(async (group) =>
+        Promise.all(
+          (await this.api.getActiveWorkerIds(group)).map((id) => this.api.assignWorkerWellknownAccount(group, id))
+        )
+      )
+    )
+  }
+}

+ 14 - 0
tests/integration-tests/src/scenarios/setupNewChain.ts

@@ -0,0 +1,14 @@
+import electCouncil from '../flows/council/elect'
+import leaderSetup from '../flows/working-groups/leadOpening'
+import updateAccountsFlow from '../misc/updateAllWorkerRoleAccountsFlow'
+import { scenario } from '../Scenario'
+
+scenario(async ({ job }) => {
+  job('Elect Council', electCouncil)
+  const leads = job('Set WorkingGroup Leads', leaderSetup)
+  job('Update worker accounts', updateAccountsFlow).after(leads)
+
+  // TODO: Mock content
+  // assign members known accounts?
+  // assign council known accounts?
+})

+ 4 - 1
tests/integration-tests/src/types.ts

@@ -99,8 +99,11 @@ export type WorkingGroupModuleName =
   | 'contentWorkingGroup'
   | 'forumWorkingGroup'
   | 'membershipWorkingGroup'
-  | 'operationsWorkingGroup'
+  | 'operationsWorkingGroupAlpha'
   | 'gatewayWorkingGroup'
+  | 'distributionWorkingGroup'
+  | 'operationsWorkingGroupBeta'
+  | 'operationsWorkingGroupGamma'
 
 // Proposals: