From bbdba19d3e9fec2c80bca6deaf40f2776989b5b4 Mon Sep 17 00:00:00 2001 From: bgallois <benjamin@gallois.cc> Date: Wed, 10 Jul 2024 10:16:20 +0200 Subject: [PATCH] add validator --- .../default/tables/public_validator.yaml | 11 +++++++ .../databases/default/tables/tables.yaml | 1 + schema.graphql | 9 +++++ src/data_handler.ts | 33 +++++++++++++------ src/genesis/genesis.ts | 7 +++- src/main.ts | 2 +- src/model/generated/index.ts | 1 + src/model/generated/smith.model.ts | 6 ++++ src/model/generated/validator.model.ts | 21 ++++++++++++ src/types_custom.ts | 4 ++- 10 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 hasura/metadata/databases/default/tables/public_validator.yaml create mode 100644 src/model/generated/validator.model.ts diff --git a/hasura/metadata/databases/default/tables/public_validator.yaml b/hasura/metadata/databases/default/tables/public_validator.yaml new file mode 100644 index 0000000..358f72a --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_validator.yaml @@ -0,0 +1,11 @@ +table: + name: validator + schema: public +object_relationships: [] +array_relationships: [] +select_permissions: + - role: public + permission: + columns: '*' + filter: {} + allow_aggregations: true diff --git a/hasura/metadata/databases/default/tables/tables.yaml b/hasura/metadata/databases/default/tables/tables.yaml index da44ca4..82ca3f8 100644 --- a/hasura/metadata/databases/default/tables/tables.yaml +++ b/hasura/metadata/databases/default/tables/tables.yaml @@ -6,6 +6,7 @@ - "!include public_enum_item_type.yaml" - "!include public_enum_counter_level.yaml" - "!include public_account.yaml" +- "!include public_validator.yaml" - "!include public_transfer.yaml" - "!include public_smith.yaml" - "!include public_enum_smith_status.yaml" diff --git a/schema.graphql b/schema.graphql index c659788..492415d 100644 --- a/schema.graphql +++ b/schema.graphql @@ -127,6 +127,13 @@ type Account @entity { isActive: Boolean! } +type Validator @entity { + "Account address is SS58 format" + id: ID! + "Identity index" + index: Int! @index +} + type Transfer @entity { blockNumber: Int! @index timestamp: DateTime! @index @@ -154,6 +161,8 @@ type Smith @entity { forged: Int! "Last forged block" lastForged: Int + "Past associated validatorId" + validatorsId: [String] @derivedFrom(field: "id") } # === this part of the schema is for Duniter pallets === diff --git a/src/data_handler.ts b/src/data_handler.ts index 0f95a5f..0015707 100644 --- a/src/data_handler.ts +++ b/src/data_handler.ts @@ -19,6 +19,7 @@ import { Transfer, UdReeval, UniversalDividend, + Validator, } from "./model"; import { Address, BlockNumber, Ctx, Data, IdtyIndex, NewData } from "./types_custom"; import { hexToString } from "./utils"; @@ -31,6 +32,7 @@ export class DataHandler { accounts: new Map(), identities: new Map(), smiths: new Map(), + validators: new Map(), membershipEvents: [], smithEvents: [], changeOwnerKey: [], @@ -183,6 +185,13 @@ export class DataHandler { idty.lastChangeOn = idtyChange.blockNumber; idty.expireOn = idtyChange.expireOn; this.data.identities.set(idtyChange.index, idty); + + const smith = await this.getSmithByIndexOrFail(ctx, idtyChange.index); + if (smith.smithStatus == SmithStatus.Smith) { + const validator = new Validator({ id: idtyChange.accountId, index: idtyChange.index }) + this.data.validators.set(idtyChange.accountId, validator); + } + this.data.smiths.set(idtyChange.index, smith); } // Process membership added @@ -334,13 +343,12 @@ export class DataHandler { } // Process validators - for (const { block, validator } of newData.validators) { - const account = await this.getAccountByAddressOrFail(ctx, validator); - const identity = await this.getIdtyByAccountOrFail(ctx, account); - const smith = await this.getSmithByIndexOrFail(ctx, identity.index); + for (const { block, validatorId } of newData.validators) { + const validator = await this.getValidatorByAddressOrFail(ctx, validatorId); + const smith = await this.getSmithByIndexOrFail(ctx, validator.index); smith.forged += 1; smith.lastForged = block - this.data.smiths.set(identity.index, smith); + this.data.smiths.set(smith.index, smith); } // Process certifications removals @@ -423,12 +431,12 @@ export class DataHandler { const { idtyIndex, event } = acceptedSmithInvitations; const smith = await this.getSmithByIndexOrFail(ctx, idtyIndex); - smith.smithStatus = SmithStatus.Smith; + smith.smithStatus = SmithStatus.Pending; smith.lastChanged = event.block.height; this.data.smiths.set(idtyIndex, smith); this.data.smithEvents.push( new SmithEvent({ - id: `smith-invited-${idtyIndex}-${event.id}`, + id: `smith-accepted-${idtyIndex}-${event.id}`, smith, eventType: SmithEventType.Accepted, event: await ctx.store.getOrFail(Event, event.id), @@ -459,6 +467,10 @@ export class DataHandler { blockNumber: event.block.height, }) ); + + const identity = await this.getIdtyWithAccountByIndexOrFail(ctx, idtyIndex); + const validator = new Validator({ id: identity.account.id, index: idtyIndex }) + this.data.validators.set(identity.account?.id, validator); } // Process Smith exlusion @@ -604,6 +616,7 @@ export class DataHandler { // identities can have been changed (confirmed, change owner key...) or added (created) await ctx.store.upsert([...this.data.smiths.values()]); await ctx.store.upsert([...this.data.identities.values()]); + await ctx.store.upsert([...this.data.validators.values()]); // membership can have been created, renewed, or removed await ctx.store.upsert([...this.data.membershipEvents.values()]); await ctx.store.upsert([...this.data.smithEvents.values()]); @@ -687,10 +700,10 @@ export class DataHandler { })) } - async getIdtyByAccountOrFail(ctx: Ctx, account: Account): Promise<Identity> { + async getValidatorByAddressOrFail(ctx: Ctx, address: Address): Promise<Validator> { return ( - account.linkedIdentity ?? - ctx.store.findOneByOrFail(Identity, { linkedAccount: account }) + this.data.validators.get(address) ?? + ctx.store.findOneByOrFail(Validator, { id: address }) ); } diff --git a/src/genesis/genesis.ts b/src/genesis/genesis.ts index c836575..c6f8b73 100644 --- a/src/genesis/genesis.ts +++ b/src/genesis/genesis.ts @@ -1,6 +1,6 @@ import { readFileSync } from "fs"; import path from "path/posix"; -import { Account, Block, Cert, CertEvent, Event, EventType, Smith, PopulationHistory, Identity, MembershipEvent, SmithEvent, SmithEventType, SmithCert, SmithStatus, Transfer } from "../model"; +import { Account, Block, Cert, CertEvent, Event, EventType, Smith, PopulationHistory, Identity, MembershipEvent, SmithEvent, SmithEventType, SmithCert, SmithStatus, Transfer, Validator } from "../model"; import type { Address, BlockV1, Certv1, Ctx, Genesis, Genv1, IdtyIndex, TransactionHistory } from "../types_custom"; import { bytesToString, hexToUint8Array, safePubkeyToAddress, v1_to_v2_height } from "../utils"; import { AccountId32 } from "../types/v800"; @@ -93,6 +93,7 @@ export async function saveGenesis(ctx: Ctx, block: Block) { const accounts: Map<Address, Account> = new Map(); const identities: Map<IdtyIndex, Identity> = new Map(); + const validators: Map<Address, Validator> = new Map(); const smiths: Map<IdtyIndex, Smith> = new Map(); const identitiesMap: Map<AccountId32, IdtyIndex> = new Map(); const certs: Map<string, Cert> = new Map(); @@ -305,6 +306,9 @@ export async function saveGenesis(ctx: Ctx, block: Block) { smiths.set(identity.index, smith); populationHistory.smithCount += 1; + const validator = new Validator({ id: identity.account.id, index: parseInt(idtyIdex) }) + validators.set(validator.id, validator); + smithsEvents.push( new SmithEvent({ id: `genesis-smith_${idtyIdex}`, @@ -329,6 +333,7 @@ export async function saveGenesis(ctx: Ctx, block: Block) { await ctx.store.insert([...smiths.values()]); await ctx.store.insert(smithsEvents); await ctx.store.insert(smithCerts); + await ctx.store.insert([...validators.values()]); ctx.log.info("Genesis saved"); diff --git a/src/main.ts b/src/main.ts index 95d79ee..e3d08f2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -99,7 +99,7 @@ function collectDataFromEvents(ctx: Ctx, newData: NewData) { const validator = block.header.validator; if (validator != null) { const blockNumber = block.header.height; - newData.validators.push({ block: blockNumber, validator: ss58encode(validator) }); + newData.validators.push({ block: blockNumber, validatorId: ss58encode(validator) }); } block.events.forEach((event) => { diff --git a/src/model/generated/index.ts b/src/model/generated/index.ts index bf13484..abf212b 100644 --- a/src/model/generated/index.ts +++ b/src/model/generated/index.ts @@ -7,6 +7,7 @@ export * from "./itemsCounter.model" export * from "./_itemType" export * from "./_counterLevel" export * from "./account.model" +export * from "./validator.model" export * from "./transfer.model" export * from "./smith.model" export * from "./_smithStatus" diff --git a/src/model/generated/smith.model.ts b/src/model/generated/smith.model.ts index 6c41231..e551c90 100644 --- a/src/model/generated/smith.model.ts +++ b/src/model/generated/smith.model.ts @@ -66,4 +66,10 @@ export class Smith { */ @Column_("int4", {nullable: true}) lastForged!: number | undefined | null + + /** + * Past associated validatorId + */ + @Column_("text", {array: true, nullable: true}) + validatorsId!: (string | undefined | null)[] | undefined | null } diff --git a/src/model/generated/validator.model.ts b/src/model/generated/validator.model.ts new file mode 100644 index 0000000..1f3673d --- /dev/null +++ b/src/model/generated/validator.model.ts @@ -0,0 +1,21 @@ +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" + +@Entity_() +export class Validator { + constructor(props?: Partial<Validator>) { + Object.assign(this, props) + } + + /** + * Account address is SS58 format + */ + @PrimaryColumn_() + id!: string + + /** + * Identity index + */ + @Index_() + @Column_("int4", {nullable: false}) + index!: number +} diff --git a/src/types_custom.ts b/src/types_custom.ts index aac44a2..9532062 100644 --- a/src/types_custom.ts +++ b/src/types_custom.ts @@ -14,6 +14,7 @@ import { Transfer, UdReeval, UniversalDividend, + Validator, } from "./model"; import { Event, ProcessorContext } from "./processor"; import { AccountId32, MembershipRemovalReason, RemovalReason, RevocationReason } from "./types/v800"; @@ -154,6 +155,7 @@ export interface Certv1 { export interface Data { accounts: Map<Address, Account>; identities: Map<IdtyIndex, Identity>; + validators: Map<Address, Validator>; smiths: Map<IdtyIndex, Smith>; membershipEvents: MembershipEvent[]; smithEvents: SmithEvent[]; @@ -259,7 +261,7 @@ interface AccountEvent { interface BlockValidator { block: BlockNumber; - validator: Address; + validatorId: Address; } interface SmithPromotedEvent { -- GitLab