Browse Source

Organize things a bit and add fill more report fields

Ricardo Maltez 4 years ago
parent
commit
7c5fa72640

+ 14 - 14
council/report-generator/report-template.md

@@ -8,21 +8,21 @@ This is a report which explains the current state of the Joystream network in nu
 
 ## 2.0 Tokenomics
 ### 2.1 Token generation breakdown
-| Property                    | Start Block | End Block | % Change |
-|-----------------------------|--------------|--------------|----------|
-| Total Tokens Minted        |              |              |          |
-| Total Tokens Burned        |              |              |          |
-| Validator Role        |              |              |          |
-| Council Role |              |              |          |
-| Storage Role       |              |              |          |
-| Curator Role       |              |              |          |
+| Property            | Start Block | End Block | % Change |
+|---------------------|--------------|--------------|----------|
+| Total Tokens Minted |              |              |          |
+| Total Tokens Burned |              |              |          |
+| Validator Role      |              |              |          |
+| Council Role        |              |              |          |
+| Storage Role        |              |              |          |
+| Curator Role        |              |              |          |
 
 ### 2.2 Mints 
-| Property                    | Start Block | End Block | % Change |
-|-----------------------------|--------------|--------------|----------|
-| Council Mint Total Minted       |              |              |          |
-| Curator Mint Total Minted |              |              |          |
-| Storage Mint Total Minted |              |              |          |
+| Property                    | Start Block           | End Block | % Change |
+|-----------------------------|-----------------------|--------------|----------|
+| Council Mint Total Minted   | {startCouncilMinted}  |  {endCouncilMinted} |{percNewCouncilMinted}          |
+| Curator Mint Total Minted   |  {startCuratorMinted} | {endCuratorMinted}| {percCuratorMinted}          |
+| Storage Mint Total Minted   |  {startStorageMinted} |  {endStorageMinted}            |  {percStorageMinted}        |
 
 ## 3.0 Council
 * Council session #: {councilRound}
@@ -39,7 +39,7 @@ This is a report which explains the current state of the Joystream network in nu
 
 ## 4 Roles
 ### 4.1 Validator Information
-* Block generation time (average):
+* Block generation time (average): {avgBlockProduction}
 
 | Property                    | Start Block | End Block | % Change |
 |-----------------------------|--------------|--------------|----------|

+ 28 - 3
council/report-generator/src/StatisticsData.ts

@@ -40,9 +40,9 @@ export class StatisticsData {
     percNewThreads: number;
 
     startPosts: number;
-    endPosts: number;
+    // endPosts: number;
     newPosts: number;
-    totalPosts: number;
+    endPosts: number;
     percNewPosts: number;
 
     startCategories: number;
@@ -61,12 +61,29 @@ export class StatisticsData {
     percNewMedia: number;
 
     deletedMedia: number;
-    createdMints: number;
+    newMints: number;
+
+    startMinted: number;
     totalMinted: number;
+    endMinted: number;
+
     totalMintCapacityIncrease: number;
 
+    startCouncilMinted: number;
+    endCouncilMinted: number;
     newCouncilMinted: number;
+    percNewCouncilMinted: number;
+
+    startCuratorMinted: number;
+    endCuratorMinted: number;
     newCuratorMinted: number;
+    percCuratorMinted: number;
+
+    startStorageMinted: number;
+    endStorageMinted: number;
+    newStorageMinted: number;
+    percStorageMinted: number;
+
 
     newTokensBurn: number;
 
@@ -123,3 +140,11 @@ export enum ProposalTypes {
     SetValidatorCount = "SetValidatorCount",
     SetStorageRoleParameters = "SetStorageRoleParameters",
 }
+
+export class MintStatistics
+{
+    startMinted: number;
+    endMinted: number;
+    diffMinted: number;
+    percMinted: number;
+}

+ 2 - 1
council/report-generator/src/generator.ts

@@ -23,7 +23,8 @@ async function main() {
             encoding: "utf8"
         });
         console.log('Getting report info...');
-        let statistics =  await StatisticsCollector.getStatistics(startBlock, endBlock);
+        let staticCollecttor = new StatisticsCollector();
+        let statistics =  await staticCollecttor.getStatistics(startBlock, endBlock);
         console.log('Writing info in the report...');
 
         let entries = Object.entries(statistics);

+ 271 - 214
council/report-generator/src/statistics.ts

@@ -3,7 +3,7 @@ import {ApiPromise, WsProvider} from "@polkadot/api";
 import {registerJoystreamTypes} from '@joystream/types';
 import {AccountId, Balance, BlockNumber, EventRecord, Hash, Moment} from "@polkadot/types/interfaces";
 
-import {Exchange, ProposalTypes, StatisticsData, ValidatorReward} from "./StatisticsData";
+import {Exchange, MintStatistics, ProposalTypes, StatisticsData, ValidatorReward} from "./StatisticsData";
 
 import {u32, Vec} from "@polkadot/types";
 import {ElectionStake, Seats} from "@joystream/types/council";
@@ -33,265 +33,322 @@ class Media {
 }
 
 export class StatisticsCollector {
-    static async getStatistics(startBlock: number, endBlock: number): Promise<StatisticsData> {
 
-        const api = await this.connectApi();
+    private api: ApiPromise;
 
-        let startHash = await api.rpc.chain.getBlockHash(startBlock);
-        let endHash = await api.rpc.chain.getBlockHash(endBlock);
+    constructor() {
 
-        let statistics = new StatisticsData();
+    }
 
-        statistics.councilRound = (await api.query.councilElection.round.at(startHash) as u32).toNumber() - COUNCIL_ROUND_OFFSET;
-        let seats = await api.query.council.activeCouncil.at(startHash) as Seats;
 
-        statistics.councilMembers = seats.length;
-        let applicants = await api.query.councilElection.applicants.at(startHash) as Vec<AccountId>;
-        statistics.electionApplicants = applicants.length;
-
-        statistics.electionApplicantsStakes = 0;
-        for (let applicant of applicants) {
-            let applicantStakes = await api.query.councilElection.applicantStakes.at(startHash, applicant) as unknown as ElectionStake;
-            statistics.electionApplicantsStakes += applicantStakes.new.toNumber();
-        }
-        statistics.electionVotes = seats.map((seat) => seat.backers.length).reduce((a, b) => a + b);
+    async getStatistics(startBlock: number, endBlock: number): Promise<StatisticsData> {
 
-        if (statistics.electionVotes) {
-            statistics.avgVotePerApplicant = statistics.electionVotes / statistics.electionApplicants;
-        } else {
-            statistics.avgVotePerApplicant = 0;
-        }
+        this.api = await StatisticsCollector.connectApi();
 
-        let startDate = await api.query.timestamp.now.at(startHash) as Moment;
-        let endDate = await api.query.timestamp.now.at(endHash) as Moment;
+        let startHash = await this.api.rpc.chain.getBlockHash(startBlock);
+        let endHash = await this.api.rpc.chain.getBlockHash(endBlock);
 
-        statistics.dateStart = new Date(startDate.toNumber()).toLocaleDateString("en-US");
-        statistics.dateEnd = new Date(endDate.toNumber()).toLocaleDateString("en-US");
+        let statistics = new StatisticsData();
 
         statistics.startBlock = startBlock;
         statistics.endBlock = endBlock;
         statistics.newBlocks = endBlock - startBlock;
-        statistics.percNewBlocks = this.convertToPercentage(statistics.newBlocks, endBlock);
-
-
-        let startIssuance = await api.query.balances.totalIssuance.at(startHash) as unknown as Balance;
-        let endIssuance = await api.query.balances.totalIssuance.at(endHash) as unknown as Balance;
-        statistics.newIssuance = endIssuance.toNumber() - startIssuance.toNumber();
-        statistics.totalIssuance = endIssuance.toNumber();
-        statistics.percNewIssuance = this.convertToPercentage(statistics.newIssuance, statistics.totalIssuance);
-
-        let startNrMembers = await api.query.members.membersCreated.at(startHash) as unknown as MemberId;
-        let endNrNumber = await api.query.members.membersCreated.at(endHash) as unknown as MemberId;
-        statistics.newMembers = endNrNumber.toNumber() - startNrMembers.toNumber();
-        statistics.totalMembers = endNrNumber.toNumber();
-        statistics.percNewMembers = this.convertToPercentage(statistics.newMembers, statistics.totalMembers);
-
+        statistics.percNewBlocks = StatisticsCollector.convertToPercentage(statistics.newBlocks, endBlock);
+        await this.fillBasicInfo(startHash, endHash, statistics);
+        await this.fillMintsData(startHash, endHash, statistics);
+        await this.fillCouncilElectionInfo(startHash, endHash, startBlock, statistics);
+        this.api.disconnect();
+        return statistics;
 
-        let startNrStakes = await api.query.stake.stakesCreated.at(startHash) as StakeId;
-        let endNrStakes = await api.query.stake.stakesCreated.at(endHash) as StakeId;
-        statistics.newStakes = endNrStakes.toNumber() - startNrStakes.toNumber();
 
-        for (let i = startNrStakes.toNumber(); i < endNrStakes.toNumber(); ++i) {
-            let stakeResult = await api.query.stake.stakes(i) as unknown as [Stake, Linkage<StakeId>];
-            let stake = stakeResult[0] as Stake;
+        //
+        // if (statistics.electionVotes) {
+        //     statistics.avgVotePerApplicant = statistics.electionVotes / statistics.electionApplicants;
+        // } else {
+        //     statistics.avgVotePerApplicant = 0;
+        // }
+        //
 
-            statistics.totalNewStakeValue += stake.value ? stake.value.toNumber() : 0;
-        }
+        //
 
-        // let startBurnedTokens = await api.query.balances.freeBalance.at(startHash, BURN_ADDRESS) as Balance;
-        // let endBurnedTokens = await api.query.balances.freeBalance.at(endHash, BURN_ADDRESS) as Balance;
         //
-        // statistics.totalBurned = endBurnedTokens.toNumber() - startBurnedTokens.toNumber();
+        //
+        // let startIssuance = await this.api.query.balances.totalIssuance.at(startHash) as unknown as Balance;
+        // let endIssuance = await this.api.query.balances.totalIssuance.at(endHash) as unknown as Balance;
+        // statistics.newIssuance = endIssuance.toNumber() - startIssuance.toNumber();
+        // statistics.totalIssuance = endIssuance.toNumber();
+        // statistics.percNewIssuance = this.convertToPercentage(statistics.newIssuance, statistics.totalIssuance);
+        //
+        // let startNrMembers = await this.api.query.members.membersCreated.at(startHash) as unknown as MemberId;
+        // let endNrNumber = await this.api.query.members.membersCreated.at(endHash) as unknown as MemberId;
+        // statistics.newMembers = endNrNumber.toNumber() - startNrMembers.toNumber();
+        // statistics.totalMembers = endNrNumber.toNumber();
+        // statistics.percNewMembers = this.convertToPercentage(statistics.newMembers, statistics.totalMembers);
+        //
+        //
+        // let startNrStakes = await this.api.query.stake.stakesCreated.at(startHash) as StakeId;
+        // let endNrStakes = await this.api.query.stake.stakesCreated.at(endHash) as StakeId;
+        // statistics.newStakes = endNrStakes.toNumber() - startNrStakes.toNumber();
+        //
+        // for (let i = startNrStakes.toNumber(); i < endNrStakes.toNumber(); ++i) {
+        //     let stakeResult = await this.api.query.stake.stakes(i) as unknown as [Stake, Linkage<StakeId>];
+        //     let stake = stakeResult[0] as Stake;
+        //
+        //     statistics.totalNewStakeValue += stake.value ? stake.value.toNumber() : 0;
+        // }
+        //
+        // // let startBurnedTokens = await this.api.query.balances.freeBalance.at(startHash, BURN_ADDRESS) as Balance;
+        // // let endBurnedTokens = await this.api.query.balances.freeBalance.at(endHash, BURN_ADDRESS) as Balance;
+        // //
+        // // statistics.totalBurned = endBurnedTokens.toNumber() - startBurnedTokens.toNumber();
+        //
+        // let startNrChannels = (await this.api.query.contentWorkingGroup.nextChannelId.at(startHash) as ChannelId).toNumber() - 1;
+        // let endNrChannels = (await this.api.query.contentWorkingGroup.nextChannelId.at(endHash) as ChannelId).toNumber() - 1;
+        //
+        // statistics.newChannels = endNrChannels - startNrChannels;
+        // statistics.totalChannels = endNrChannels;
+        // statistics.percNewChannels = this.convertToPercentage(statistics.newChannels, statistics.totalChannels);
+        //
+        // let startMedias = await this.getMedia(api, startHash);
+        // let endMedias = await this.getMedia(api, endHash);
+        //
+        // let newMedia = endMedias.filter((endMedia) => {
+        //     return !startMedias.some((startMedia) => startMedia.id == endMedia.id);
+        // });
+        //
+        // statistics.newMedia = newMedia.length;
+        // statistics.totalMedia = endMedias.length;
+        // statistics.percNewMedia = this.convertToPercentage(statistics.newMedia, statistics.totalMedia);
+        //
+        // let startDataObjects = await this.api.query.dataDirectory.knownContentIds.at(startHash) as Vec<ContentId>;
+        // let startUsedSpace = await this.computeUsedSpaceInBytes(api, startDataObjects);
+        //
+        // let endDataObjects = await this.api.query.dataDirectory.knownContentIds.at(endHash) as Vec<ContentId>;
+        // let endUsedSpace = await this.computeUsedSpaceInBytes(api, endDataObjects);
+        //
+        // statistics.newUsedSpace = endUsedSpace - startUsedSpace;
+        // statistics.totalUsedSpace = endUsedSpace;
+        // statistics.percNewUsedSpace = this.convertToPercentage(statistics.newUsedSpace, statistics.totalUsedSpace);
+        //
+        // statistics.avgNewSizePerContent = Number((statistics.newUsedSpace / statistics.newMedia).toFixed(2));
+        // statistics.totalAvgSizePerContent = Number((statistics.totalUsedSpace / statistics.totalMedia).toFixed(2));
+        // statistics.percAvgSizePerContent = this.convertToPercentage(statistics.avgNewSizePerContent, statistics.totalAvgSizePerContent);
+        //
+        // //
+        // // for (let startMedia of startMedias) {
+        // //     let deleted = !endMedias.some((endMedia) => {
+        // //         return endMedia.id == startMedia.id;
+        // //     })
+        // //     if (deleted) {
+        // //         ++statistics.deletedMedia;
+        // //     }
+        // // }
+        //
+        // let startTimestamp = await this.api.query.timestamp.now.at(startHash) as unknown as Moment;
+        // let endTimestamp = await this.api.query.timestamp.now.at(endHash) as unknown as Moment;
+        // let avgBlockProduction = (((endTimestamp.toNumber() - startTimestamp.toNumber())
+        //     / 1000) / statistics.newBlocks);
+        // statistics.avgBlockProduction = Number(avgBlockProduction.toFixed(2));
+        //
+        // let startPostId = await this.api.query.forum.nextPostId.at(startHash) as unknown as PostId;
+        // let endPostId = await this.api.query.forum.nextPostId.at(endHash) as unknown as PostId;
+        // statistics.startPosts = startPostId.toNumber() - 1;
+        // statistics.newPosts = endPostId.toNumber() - startPostId.toNumber();
+        // statistics.endPosts = endPostId.toNumber() - 1;
+        // statistics.percNewPosts = this.convertToPercentage(statistics.newPosts, statistics.endPosts);
+        //
+        // let startThreadId = await this.api.query.forum.nextThreadId.at(startHash) as unknown as ThreadId;
+        // let endThreadId = await this.api.query.forum.nextThreadId.at(endHash) as unknown as ThreadId;
+        // statistics.newThreads = endThreadId.toNumber() - startThreadId.toNumber();
+        // statistics.totalThreads = endThreadId.toNumber() - 1;
+        // statistics.percNewThreads = this.convertToPercentage(statistics.newThreads, statistics.totalThreads);
+        //
+        // let startCategoryId = await this.api.query.forum.nextCategoryId.at(startHash) as unknown as CategoryId;
+        // let endCategoryId = await this.api.query.forum.nextCategoryId.at(endHash) as unknown as CategoryId;
+        // statistics.newCategories = endCategoryId.toNumber() - startCategoryId.toNumber();
+        //
+        // let startNrProposals = await this.api.query.proposalsEngine.proposalCount.at(startHash) as unknown as u32;
+        // let endNrProposals = await this.api.query.proposalsEngine.proposalCount.at(endHash) as unknown as u32;
+        // statistics.newProposals = endNrProposals.toNumber() - startNrProposals.toNumber();
+        //
+        // for (let i = startNrProposals.toNumber(); i < endNrProposals.toNumber(); ++i) {
+        //     let proposalNumber = i - 1;
+        //     let proposalDetails = await this.api.query.proposalsCodex.proposalDetailsByProposalId.at(endHash, proposalNumber) as ProposalDetails;
+        //     switch (proposalDetails.type) {
+        //         case ProposalTypes.Text:
+        //             ++statistics.newTextProposals;
+        //             break;
+        //
+        //         case ProposalTypes.RuntimeUpgrade:
+        //             ++statistics.newRuntimeUpgradeProposal;
+        //             break;
+        //
+        //         case ProposalTypes.SetElectionParameters:
+        //             ++statistics.newSetElectionParametersProposal;
+        //             break;
+        //
+        //         case ProposalTypes.Spending:
+        //             ++statistics.newSpendingProposal;
+        //             break;
+        //
+        //         case ProposalTypes.SetLead:
+        //             ++statistics.newSetLeadProposal;
+        //             break;
+        //
+        //         case ProposalTypes.SetContentWorkingGroupMintCapacity:
+        //             ++statistics.newSetContentWorkingGroupMintCapacityProposal;
+        //             break;
+        //
+        //         case ProposalTypes.EvictStorageProvider:
+        //             ++statistics.newEvictStorageProviderProposal;
+        //             break;
+        //
+        //         case ProposalTypes.SetValidatorCount:
+        //             ++statistics.newSetValidatorCountProposal;
+        //             break;
+        //
+        //         case ProposalTypes.SetStorageRoleParameters:
+        //             ++statistics.newSetStorageRoleParametersProposal;
+        //             break;
+        //     }
+        // }
+        //
+        // let validatorRewards: ValidatorReward[] = [];
+        // let exchangesCollection: Exchange[] = [];
+        // let promises = [];
+        //
+        // console.time('extractValidatorsRewards');
+        // for (let i = startBlock; i < endBlock; ++i) {
+        //     let promise = (async () => {
+        //         const blockHash: Hash = await this.api.rpc.chain.getBlockHash(i);
+        //         const events = await this.api.query.system.events.at(blockHash) as Vec<EventRecord>;
+        //         let rewards = await this.extractValidatorsRewards(api, i, events);
+        //         if (rewards.length) {
+        //             validatorRewards = validatorRewards.concat(rewards);
+        //         }
+        //         let exchanges = this.extractExchanges(i, events);
+        //         if (exchanges.length) {
+        //             exchangesCollection = exchangesCollection.concat(exchanges);
+        //         }
+        //
+        //     })();
+        //     promises.push(promise);
+        // }
+        // await Promise.all(promises);
+        // console.timeEnd('extractValidatorsRewards');
+        //
+        // statistics.newValidatorReward = validatorRewards.map((validatorReward) => validatorReward.sharedReward).reduce((a, b) => a + b);
+        // let avgValidators = validatorRewards.map((validatorReward) => validatorReward.validators).reduce((a, b) => a + b) / validatorRewards.length;
+        // statistics.avgValidators = Number(avgValidators.toFixed(2));
+        //
+        // statistics.newTokensBurn = exchangesCollection.map((exchange) => exchange.amount).reduce((a, b) => a + b);
+        //
+        // statistics.newStorageProviderReward = await this.computeStorageRewards(api, startBlock, endBlock);
+        //
+        // this.api.disconnect();
+        // return statistics;
+    }
 
+    async fillBasicInfo(startHash: Hash, endHash: Hash, statistics: StatisticsData) {
+        let startDate = await this.api.query.timestamp.now.at(startHash) as Moment;
+        let endDate = await this.api.query.timestamp.now.at(endHash) as Moment;
+        statistics.dateStart = new Date(startDate.toNumber()).toLocaleDateString("en-US");
+        statistics.dateEnd = new Date(endDate.toNumber()).toLocaleDateString("en-US");
 
+    }
 
-        let startNrMints = parseInt((await api.query.minting.mintsCreated.at(startHash)).toString());
-        let endNrMints = parseInt((await api.query.minting.mintsCreated.at(endHash)).toString());
 
-        statistics.createdMints = endNrMints - startNrMints;
+    async fillMintsData(startHash: Hash, endHash: Hash, statistics: StatisticsData) {
 
+        let startNrMints = parseInt((await this.api.query.minting.mintsCreated.at(startHash)).toString());
+        let endNrMints = parseInt((await this.api.query.minting.mintsCreated.at(endHash)).toString());
+
+        statistics.newMints = endNrMints - startNrMints;
+        // statistics.startMinted = 0;
+        // statistics.endMinted = 0;
         for (let i = 0; i < startNrMints; ++i) {
-            let startMintResult = await api.query.minting.mints.at(startHash, i) as unknown as [Mint, Linkage<MintId>];
+            let startMintResult = await this.api.query.minting.mints.at(startHash, i) as unknown as [Mint, Linkage<MintId>];
             let startMint = startMintResult[0];
 
-            let endMintResult = await api.query.minting.mints.at(endHash, i) as unknown as [Mint, Linkage<MintId>];
+            let endMintResult = await this.api.query.minting.mints.at(endHash, i) as unknown as [Mint, Linkage<MintId>];
             let endMint = endMintResult[0];
 
-            statistics.totalMinted = parseInt(endMint.getField('total_minted').toString()) - parseInt(startMint.getField('total_minted').toString());
-            statistics.totalMintCapacityIncrease = parseInt(endMint.getField('capacity').toString()) - -parseInt(startMint.getField('capacity').toString());
+            let startMintTotal = parseInt(startMint.getField('total_minted').toString());
+            let endMintTotal = parseInt(endMint.getField('total_minted').toString());
+
+            // statistics.startMinted += startMintTotal;
+
+            statistics.totalMinted += endMintTotal - startMintTotal;
+            statistics.totalMintCapacityIncrease += parseInt(endMint.getField('capacity').toString()) - parseInt(startMint.getField('capacity').toString());
         }
 
         for (let i = startNrMints; i < endNrMints; ++i) {
-            let endMintResult = await api.query.minting.mints.at(endHash, i) as unknown as [Mint, Linkage<MintId>];
+            let endMintResult = await this.api.query.minting.mints.at(endHash, i) as unknown as [Mint, Linkage<MintId>];
             let endMint = endMintResult[0] as Mint;
             statistics.totalMinted = parseInt(endMint.getField('total_minted').toString());
         }
 
-        let councilMint = await api.query.council.councilMint.at(endHash) as Option<MintId>;
-        let curatorMint = await api.query.contentWorkingGroup.mint.at(endHash) as MintId;
+        let councilMint = await this.api.query.council.councilMint.at(endHash) as Option<MintId>;
+        let councilMintStatistics = await this.computeMintInfo(councilMint.unwrap(), startHash, endHash);
+
+        statistics.startCouncilMinted = councilMintStatistics.startMinted;
+        statistics.endCouncilMinted = councilMintStatistics.endMinted
+        statistics.newCouncilMinted = councilMintStatistics.diffMinted;
+        statistics.percNewCouncilMinted = councilMintStatistics.percMinted;
+
+        let curatorMint = await this.api.query.contentWorkingGroup.mint.at(endHash) as MintId;
+        let curatorMintStatistics = await this.computeMintInfo(curatorMint, startHash, endHash);
+        statistics.startCuratorMinted = curatorMintStatistics.startMinted;
+        statistics.endCuratorMinted = curatorMintStatistics.endMinted;
+        statistics.newCuratorMinted = curatorMintStatistics.diffMinted;
+        statistics.percCuratorMinted = curatorMintStatistics.percMinted;
+
+        let storageProviderMint = await this.api.query.storageWorkingGroup.mint.at(endHash) as MintId;
+        let storageProviderMintStatistics = await this.computeMintInfo(storageProviderMint, startHash, endHash);
+        statistics.startStorageMinted = storageProviderMintStatistics.startMinted;
+        statistics.endStorageMinted = storageProviderMintStatistics.endMinted;
+        statistics.newStorageMinted = storageProviderMintStatistics.diffMinted;
+        statistics.percStorageMinted = storageProviderMintStatistics.percMinted;
+    }
 
-        let startCouncilMintResult = await api.query.minting.mints.at(startHash, councilMint.unwrap()) as unknown as [Mint, Linkage<MintId>];
+    async computeMintInfo(mintId: MintId, startHash: Hash, endHash: Hash): Promise<MintStatistics> {
+        let startCouncilMintResult = await this.api.query.minting.mints.at(startHash, mintId) as unknown as [Mint, Linkage<MintId>];
         let startCouncilMint = startCouncilMintResult[0] as unknown as Mint;
 
-        let endCouncilMintResult = await api.query.minting.mints.at(endHash, councilMint.unwrap()) as unknown as [Mint, Linkage<MintId>];
+        let endCouncilMintResult = await this.api.query.minting.mints.at(endHash, mintId) as unknown as [Mint, Linkage<MintId>];
         let endCouncilMint = endCouncilMintResult[0] as unknown as Mint;
 
-        let startCuratorMintResult = await api.query.minting.mints.at(startHash, curatorMint.toNumber()) as unknown as [Mint, Linkage<MintId>];
-        let startCuratorMint = startCuratorMintResult[0] as unknown as Mint;
-
-        let endCuratorMintResult = await api.query.minting.mints.at(endHash, curatorMint.toNumber()) as unknown as [Mint, Linkage<MintId>];
-        let endCuratorMint = endCuratorMintResult[0] as unknown as Mint;
-
-        statistics.newCouncilMinted = parseInt(endCouncilMint.getField('total_minted').toString()) - parseInt(startCouncilMint.getField('total_minted').toString());
-        statistics.newCuratorMinted = parseInt(endCuratorMint.getField('total_minted').toString()) - parseInt(startCuratorMint.getField('total_minted').toString());
-
-        let startNrChannels = (await api.query.contentWorkingGroup.nextChannelId.at(startHash) as ChannelId).toNumber() - 1;
-        let endNrChannels = (await api.query.contentWorkingGroup.nextChannelId.at(endHash) as ChannelId).toNumber() - 1;
-
-        statistics.newChannels = endNrChannels - startNrChannels;
-        statistics.totalChannels = endNrChannels;
-        statistics.percNewChannels = this.convertToPercentage(statistics.newChannels, statistics.totalChannels);
-
-        let startMedias = await this.getMedia(api, startHash);
-        let endMedias = await this.getMedia(api, endHash);
-
-        let newMedia = endMedias.filter((endMedia) => {
-            return !startMedias.some((startMedia) => startMedia.id == endMedia.id);
-        });
-
-        statistics.newMedia = newMedia.length;
-        statistics.totalMedia = endMedias.length;
-        statistics.percNewMedia = this.convertToPercentage(statistics.newMedia, statistics.totalMedia);
-
-        let startDataObjects = await api.query.dataDirectory.knownContentIds.at(startHash) as Vec<ContentId>;
-        let startUsedSpace = await this.computeUsedSpaceInBytes(api, startDataObjects);
-
-        let endDataObjects = await api.query.dataDirectory.knownContentIds.at(endHash) as Vec<ContentId>;
-        let endUsedSpace = await this.computeUsedSpaceInBytes(api, endDataObjects);
-
-        statistics.newUsedSpace = endUsedSpace - startUsedSpace;
-        statistics.totalUsedSpace = endUsedSpace;
-        statistics.percNewUsedSpace = this.convertToPercentage(statistics.newUsedSpace, statistics.totalUsedSpace);
-
-        statistics.avgNewSizePerContent = Number((statistics.newUsedSpace / statistics.newMedia).toFixed(2));
-        statistics.totalAvgSizePerContent = Number((statistics.totalUsedSpace / statistics.totalMedia).toFixed(2));
-        statistics.percAvgSizePerContent = this.convertToPercentage(statistics.avgNewSizePerContent, statistics.totalAvgSizePerContent);
+        let mintStatistics = new MintStatistics();
+        mintStatistics.startMinted = parseInt(startCouncilMint.getField('total_minted').toString());
+        mintStatistics.endMinted = parseInt(endCouncilMint.getField('total_minted').toString());
+        mintStatistics.diffMinted = mintStatistics.endMinted - mintStatistics.startMinted;
+        mintStatistics.percMinted = StatisticsCollector.convertToPercentage(mintStatistics.diffMinted, mintStatistics.endMinted);
+        return mintStatistics;
+    }
 
-        //
-        // for (let startMedia of startMedias) {
-        //     let deleted = !endMedias.some((endMedia) => {
-        //         return endMedia.id == startMedia.id;
-        //     })
-        //     if (deleted) {
-        //         ++statistics.deletedMedia;
-        //     }
-        // }
+    async fillCouncilElectionInfo(startHash: Hash, endHash: Hash, startBlock: number, statistics: StatisticsData) {
+        statistics.councilRound = (await this.api.query.councilElection.round.at(startHash) as u32).toNumber() - COUNCIL_ROUND_OFFSET;
+        let seats = await this.api.query.council.activeCouncil.at(startHash) as Seats;
+        statistics.councilMembers = seats.length;
 
-        let startTimestamp = await api.query.timestamp.now.at(startHash) as unknown as Moment;
-        let endTimestamp = await api.query.timestamp.now.at(endHash) as unknown as Moment;
-        let avgBlockProduction = (((endTimestamp.toNumber() - startTimestamp.toNumber())
-            / 1000) / statistics.newBlocks);
-        statistics.avgBlockProduction = Number(avgBlockProduction.toFixed(2));
-
-        let startPostId = await api.query.forum.nextPostId.at(startHash) as unknown as PostId;
-        let endPostId = await api.query.forum.nextPostId.at(endHash) as unknown as PostId;
-        statistics.newPosts = endPostId.toNumber() - startPostId.toNumber();
-        statistics.totalPosts = endPostId.toNumber() - 1;
-        statistics.percNewPosts = this.convertToPercentage(statistics.newPosts, statistics.totalPosts);
-
-        let startThreadId = await api.query.forum.nextThreadId.at(startHash) as unknown as ThreadId;
-        let endThreadId = await api.query.forum.nextThreadId.at(endHash) as unknown as ThreadId;
-        statistics.newThreads = endThreadId.toNumber() - startThreadId.toNumber();
-        statistics.totalThreads = endThreadId.toNumber() - 1;
-        statistics.percNewThreads = this.convertToPercentage(statistics.newThreads, statistics.totalThreads);
-
-        let startCategoryId = await api.query.forum.nextCategoryId.at(startHash) as unknown as CategoryId;
-        let endCategoryId = await api.query.forum.nextCategoryId.at(endHash) as unknown as CategoryId;
-        statistics.newCategories = endCategoryId.toNumber() - startCategoryId.toNumber();
-
-        let startNrProposals = await api.query.proposalsEngine.proposalCount.at(startHash) as unknown as u32;
-        let endNrProposals = await api.query.proposalsEngine.proposalCount.at(endHash) as unknown as u32;
-        statistics.newProposals = endNrProposals.toNumber() - startNrProposals.toNumber();
-
-        for (let i = startNrProposals.toNumber(); i < endNrProposals.toNumber(); ++i) {
-            let proposalNumber = i - 1;
-            let proposalDetails = await api.query.proposalsCodex.proposalDetailsByProposalId.at(endHash, proposalNumber) as ProposalDetails;
-            switch (proposalDetails.type) {
-                case ProposalTypes.Text:
-                    ++statistics.newTextProposals;
-                    break;
-
-                case ProposalTypes.RuntimeUpgrade:
-                    ++statistics.newRuntimeUpgradeProposal;
-                    break;
-
-                case ProposalTypes.SetElectionParameters:
-                    ++statistics.newSetElectionParametersProposal;
-                    break;
-
-                case ProposalTypes.Spending:
-                    ++statistics.newSpendingProposal;
-                    break;
-
-                case ProposalTypes.SetLead:
-                    ++statistics.newSetLeadProposal;
-                    break;
-
-                case ProposalTypes.SetContentWorkingGroupMintCapacity:
-                    ++statistics.newSetContentWorkingGroupMintCapacityProposal;
-                    break;
-
-                case ProposalTypes.EvictStorageProvider:
-                    ++statistics.newEvictStorageProviderProposal;
-                    break;
-
-                case ProposalTypes.SetValidatorCount:
-                    ++statistics.newSetValidatorCountProposal;
-                    break;
-
-                case ProposalTypes.SetStorageRoleParameters:
-                    ++statistics.newSetStorageRoleParametersProposal;
-                    break;
-            }
-        }
+        let applicants: Vec<AccountId>
+        let currentSearchBlock = startBlock - 1;
+        do {
+            let applicantHash = await this.api.rpc.chain.getBlockHash(currentSearchBlock);
+            applicants = await this.api.query.councilElection.applicants.at(applicantHash) as Vec<AccountId>;
+            --currentSearchBlock;
+        } while (applicants.length == 0);
 
-        let validatorRewards: ValidatorReward[] = [];
-        let exchangesCollection: Exchange[] = [];
-        let promises = [];
-
-        console.time('extractValidatorsRewards');
-        for (let i = startBlock; i < endBlock; ++i) {
-            let promise = (async () => {
-                const blockHash: Hash = await api.rpc.chain.getBlockHash(i);
-                const events = await api.query.system.events.at(blockHash) as Vec<EventRecord>;
-                let rewards = await this.extractValidatorsRewards(api, i, events);
-                if (rewards.length) {
-                    validatorRewards = validatorRewards.concat(rewards);
-                }
-                let exchanges = this.extractExchanges(i, events);
-                if (exchanges.length) {
-                    exchangesCollection = exchangesCollection.concat(exchanges);
-                }
+        statistics.electionApplicants = applicants.length;
 
-            })();
-            promises.push(promise);
+        statistics.electionApplicantsStakes = 0;
+        for (let applicant of applicants) {
+            let applicantStakes = await this.api.query.councilElection.applicantStakes.at(startHash, applicant) as unknown as ElectionStake;
+            statistics.electionApplicantsStakes += applicantStakes.new.toNumber();
         }
-        await Promise.all(promises);
-        console.timeEnd('extractValidatorsRewards');
-
-        statistics.newValidatorReward = validatorRewards.map((validatorReward) => validatorReward.sharedReward).reduce((a, b) => a + b);
-        let avgValidators = validatorRewards.map((validatorReward) => validatorReward.validators).reduce((a, b) => a + b) / validatorRewards.length;
-        statistics.avgValidators = Number(avgValidators.toFixed(2));
-
-        statistics.newTokensBurn = exchangesCollection.map((exchange) => exchange.amount).reduce((a, b) => a + b);
-
-        statistics.newStorageProviderReward = await this.computeStorageRewards(api, startBlock, endBlock);
-
-        api.disconnect();
-        return statistics;
+        statistics.electionVotes = seats.map((seat) => seat.backers.length).reduce((a, b) => a + b);
     }
 
-
     static async extractValidatorsRewards(api: ApiPromise, blockNumber: number, events: Vec<EventRecord>): Promise<ValidatorReward[]> {
         let valRewards = [];
         // const api = await this.connectApi();