From ac4f093e0de33abf5bc03e45ed089f03e2343c4b Mon Sep 17 00:00:00 2001
From: Hugo Trentesaux <hugo@trentesaux.fr>
Date: Tue, 5 Nov 2024 16:10:10 +0100
Subject: [PATCH] add account creation block

see issue #39
---
 ...30204747165-Data.js => 1730814071971-Data.js} |  6 +++---
 ...ration.js => 1730814191993-EnumsMigration.js} |  4 ++--
 ...ion.js => 1730814191993-udHistoryFunction.js} |  4 ++--
 schema.graphql                                   |  3 +++
 src/data_handler.ts                              | 16 ++++++++--------
 src/genesis/genesis.ts                           |  3 +++
 src/main.ts                                      |  5 ++++-
 src/model/generated/account.model.ts             |  8 +++++++-
 src/types_custom.ts                              |  7 ++++++-
 9 files changed, 38 insertions(+), 18 deletions(-)
 rename db/migrations/{1730204747165-Data.js => 1730814071971-Data.js} (99%)
 rename db/migrations/{1730204867181-EnumsMigration.js => 1730814191993-EnumsMigration.js} (72%)
 rename db/migrations/{1730204867181-udHistoryFunction.js => 1730814191993-udHistoryFunction.js} (71%)

diff --git a/db/migrations/1730204747165-Data.js b/db/migrations/1730814071971-Data.js
similarity index 99%
rename from db/migrations/1730204747165-Data.js
rename to db/migrations/1730814071971-Data.js
index a312cb2..e479c0b 100644
--- a/db/migrations/1730204747165-Data.js
+++ b/db/migrations/1730814071971-Data.js
@@ -1,5 +1,5 @@
-module.exports = class Data1730204747165 {
-    name = 'Data1730204747165'
+module.exports = class Data1730814071971 {
+    name = 'Data1730814071971'
 
     async up(db) {
         await db.query(`CREATE TABLE "event" ("id" character varying NOT NULL, "index" integer NOT NULL, "phase" text NOT NULL, "pallet" text NOT NULL, "name" text NOT NULL, "args" jsonb, "args_str" text array, "block_id" character varying, "extrinsic_id" character varying, "call_id" character varying, CONSTRAINT "PK_30c2f3bbaf6d34a55f8ae6e4614" PRIMARY KEY ("id"))`)
@@ -79,7 +79,7 @@ module.exports = class Data1730204747165 {
         await db.query(`CREATE INDEX "IDX_f4007436c1b546ede08a4fd7ab" ON "transfer" ("amount") `)
         await db.query(`CREATE INDEX "IDX_2a4e1dce9f72514cd28f554ee2" ON "transfer" ("event_id") `)
         await db.query(`CREATE INDEX "IDX_76cf30dd4464ed95ad44c5bb61" ON "transfer" ("comment_id") `)
-        await db.query(`CREATE TABLE "account" ("id" character varying NOT NULL, "is_active" boolean NOT NULL, "linked_identity_id" character varying, CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`)
+        await db.query(`CREATE TABLE "account" ("id" character varying NOT NULL, "created_on" integer NOT NULL, "is_active" boolean NOT NULL, "linked_identity_id" character varying, CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`)
         await db.query(`CREATE INDEX "IDX_73d14d249a6dcf9abe42eaa657" ON "account" ("linked_identity_id") `)
         await db.query(`CREATE TABLE "validator" ("id" character varying NOT NULL, "index" integer NOT NULL, CONSTRAINT "PK_ae0a943022c24bd60e7161e0fad" PRIMARY KEY ("id"))`)
         await db.query(`CREATE INDEX "IDX_49842e345355a71ff691c7a1ee" ON "validator" ("index") `)
diff --git a/db/migrations/1730204867181-EnumsMigration.js b/db/migrations/1730814191993-EnumsMigration.js
similarity index 72%
rename from db/migrations/1730204867181-EnumsMigration.js
rename to db/migrations/1730814191993-EnumsMigration.js
index 346fca2..2c304b4 100644
--- a/db/migrations/1730204867181-EnumsMigration.js
+++ b/db/migrations/1730814191993-EnumsMigration.js
@@ -1,7 +1,7 @@
 const fs = require("fs");
 
-module.exports = class EnumsMigration1730204867181 {
-  name = "EnumsMigration1730204867181";
+module.exports = class EnumsMigration1730814191993 {
+  name = "EnumsMigration1730814191993";
 
   async up(db) {
     await db.query(fs.readFileSync("assets/sql/EnumsMigration_up.sql", "utf8"));
diff --git a/db/migrations/1730204867181-udHistoryFunction.js b/db/migrations/1730814191993-udHistoryFunction.js
similarity index 71%
rename from db/migrations/1730204867181-udHistoryFunction.js
rename to db/migrations/1730814191993-udHistoryFunction.js
index 277bcff..76a158a 100644
--- a/db/migrations/1730204867181-udHistoryFunction.js
+++ b/db/migrations/1730814191993-udHistoryFunction.js
@@ -1,7 +1,7 @@
 const fs = require("fs");
 
-module.exports = class udHistoryFunction1730204867181 {
-  name = "udHistoryFunction1730204867181";
+module.exports = class udHistoryFunction1730814191993 {
+  name = "udHistoryFunction1730814191993";
 
   async up(db) {
     await db.query(fs.readFileSync("assets/sql/udHistoryFunction_up.sql", "utf8"));
diff --git a/schema.graphql b/schema.graphql
index 372232b..80aa552 100644
--- a/schema.graphql
+++ b/schema.graphql
@@ -114,6 +114,9 @@ type ItemsCounter @entity {
 type Account @entity {
   "Account address is SS58 format"
   id: ID!
+  "Block number of account creation"
+  # if account is created multiple times, this is the first creation block
+  createdOn: Int!
   "current account for the identity"
   identity: Identity @derivedFrom(field: "account")
   "removed identities on this account"
diff --git a/src/data_handler.ts b/src/data_handler.ts
index 8b2aa21..6c6c629 100644
--- a/src/data_handler.ts
+++ b/src/data_handler.ts
@@ -70,10 +70,10 @@ export class DataHandler {
     }
 
     // Process accounts
-    for (const accountId of newData.accounts) {
-      const newAccount = new Account({ id: accountId, isActive: true });
-      this.data.accounts.set(accountId, newAccount);
-      ctx.log.info(`Added account ${accountId}`);
+    for (const accountevt of newData.accounts) {
+      const newAccount = new Account({ id: accountevt.address, createdOn: accountevt.blockNumber, isActive: true });
+      this.data.accounts.set(accountevt.address, newAccount);
+      ctx.log.info(`Added account ${accountevt}`);
     }
 
     // Process killed accounts
@@ -577,7 +577,7 @@ export class DataHandler {
   async handleNewAccountsApart(ctx: Ctx, newData: NewData) {
     // Combine account and account link sets to get unique candidates
     const newAccountCandidates = new Set<Address>([
-      ...newData.accounts,
+      ...newData.accounts.map(a => a.address),
       ...newData.accountLink.map((link) => link.accountId),
     ]);
 
@@ -595,9 +595,9 @@ export class DataHandler {
     );
 
     // Filter and create accounts that don't already exist
-    const accountsToCreate = [...newAccountCandidates]
-      .filter((id) => !existingAccountIds.has(id))
-      .map((id) => new Account({ id, isActive: true }));
+    const accountsToCreate = newData.accounts
+      .filter(a => !existingAccountIds.has(a.address))
+      .map(a => new Account({ id: a.address, createdOn: a.blockNumber, isActive: true }));
 
     if (accountsToCreate.length > 0) {
       await ctx.store.insert(accountsToCreate);
diff --git a/src/genesis/genesis.ts b/src/genesis/genesis.ts
index 25c218f..4bf77bf 100644
--- a/src/genesis/genesis.ts
+++ b/src/genesis/genesis.ts
@@ -139,6 +139,7 @@ export async function saveGenesis(ctx: Ctx, block: Block) {
         isActive,
         // init to null and update later to handle circular dependency
         linkedIdentity: null,
+        createdOn: 0 // TODO track block creation of v1 account
       })
     );
     if (isActive) {
@@ -388,6 +389,7 @@ export async function saveGenesis(ctx: Ctx, block: Block) {
       accounts.set(issuer, new Account({
         id: issuer,
         isActive: false,
+        createdOn: 0 // TODO track block creation of v1 account
       }));
     }
     if (!accounts.has(receiver)) {
@@ -395,6 +397,7 @@ export async function saveGenesis(ctx: Ctx, block: Block) {
       accounts.set(receiver, new Account({
         id: receiver,
         isActive: false,
+        createdOn: 0 // TODO track block creation of v1 account
       }));
     }
   }
diff --git a/src/main.ts b/src/main.ts
index 980ee46..3b86af2 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -115,7 +115,10 @@ function collectDataFromEvents(ctx: Ctx, newData: NewData) {
       switch (event.name) {
         case events_t.system.newAccount.name: {
           const evt = events_t.system.newAccount.v800.decode(event);
-          newData.accounts.push(ss58encode(evt.account));
+          newData.accounts.push({
+            address: ss58encode(evt.account),
+            blockNumber: block.header.height
+          });
           acc.activeAccountCount += 1;
           acc.blockNumber = block.header.height;
           break;
diff --git a/src/model/generated/account.model.ts b/src/model/generated/account.model.ts
index 3e4928d..117e590 100644
--- a/src/model/generated/account.model.ts
+++ b/src/model/generated/account.model.ts
@@ -1,4 +1,4 @@
-import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, OneToOne as OneToOne_, OneToMany as OneToMany_, ManyToOne as ManyToOne_, Index as Index_, BooleanColumn as BooleanColumn_} from "@subsquid/typeorm-store"
+import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, IntColumn as IntColumn_, OneToOne as OneToOne_, OneToMany as OneToMany_, ManyToOne as ManyToOne_, Index as Index_, BooleanColumn as BooleanColumn_} from "@subsquid/typeorm-store"
 import {Identity} from "./identity.model"
 import {ChangeOwnerKey} from "./changeOwnerKey.model"
 import {Transfer} from "./transfer.model"
@@ -19,6 +19,12 @@ export class Account {
     @PrimaryColumn_()
     id!: string
 
+    /**
+     * Block number of account creation
+     */
+    @IntColumn_({nullable: false})
+    createdOn!: number
+
     /**
      * current account for the identity
      */
diff --git a/src/types_custom.ts b/src/types_custom.ts
index e1c6005..b8d461a 100644
--- a/src/types_custom.ts
+++ b/src/types_custom.ts
@@ -176,7 +176,7 @@ export interface Data {
 // a way to group data returned from events
 // this contains partial data to be turned into types
 export interface NewData {
-  accounts: Address[];
+  accounts: NewAccountEvent[];
   killedAccounts: Address[];
   validators: BlockValidator[];
   populationHistories: AccPopulationHistory[];
@@ -232,6 +232,11 @@ interface UdReevalEvent {
   event: Event;
 }
 
+interface NewAccountEvent {
+  blockNumber: BlockNumber;
+  address: Address
+}
+
 interface TransferEvent {
   id: string;
   blockNumber: BlockNumber;
-- 
GitLab