diff --git a/README-2.md b/README-2.md index 97fea1f07df0f3f0e20defa465312ef270fd4f4d..fbf3c87b17ea47fc546d5e3077c7da9cc4ee2ff5 100644 --- a/README-2.md +++ b/README-2.md @@ -1,4 +1,10 @@ -# Processus de mise-à-jour +## Installation d'outils + +```sh +pnpm install --global @subsquid/cli@latest +``` + +## Processus de mise-à-jour du runtime Pour mettre à jour les métadonnées du runtime @@ -7,9 +13,20 @@ pnpm install --global @subsquid/substrate-metadata-explorer squid-substrate-metadata-explorer --rpc ws://127.0.0.1:9944 --out gdev-metadata.jsonl ``` +## Processus de mise-à-jour du réseau + Pour mettre à jour les assets (nouveau réseau) ```sh # copier le lien depuis https://git.duniter.org/nodes/rust/duniter-v2s/-/releases/ wget https://nodes.pages.duniter.org/-/rust/duniter-v2s/-/jobs/120948/artifacts/release/gdev.json -O ./assets/gdev.json +``` + +## Publication d'image docker + +Ce que je fais pour publier l'image + +```sh +docker build . -t h30x/duniter-squid +docker image push h30x/duniter-squid ``` \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index b5c5add7086d2b558436e19703805d9354d2959a..f40fd0b9cf7dea0a5172520ca4685ada377b1e2d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -50,7 +50,7 @@ processor.run(new TypeormDatabaseWithCache(), async (ctx) => { getNewData(ctx, ndata); // transform new data to objects - let prepared: PreparedData = { + let data: Data = { accounts: new Map(), identities: new Map(), changeOwnerKey: [], @@ -60,10 +60,10 @@ processor.run(new TypeormDatabaseWithCache(), async (ctx) => { certRenewal: [], certRemoval: [], }; - await prepareData(ctx, ndata, prepared); + await prepareData(ctx, ndata, data); // store data - await storeData(ctx, prepared); + await storeData(ctx, data); }); // ===================================================================================================== @@ -72,6 +72,7 @@ processor.run(new TypeormDatabaseWithCache(), async (ctx) => { export type Address = string; export type IdtyIndex = number; type BlockNumber = number; +type Ctx = ProcessorContext<StoreWithCache>; // a way to group data returned from events // this contains partial data to be turned into types @@ -117,7 +118,7 @@ interface CertRemovalEvent { interface IdtyCreatedEvent { id: string; index: IdtyIndex; - account: Address; + accountId: Address; } interface IdtyConfirmedEvent { id: string; @@ -127,12 +128,12 @@ interface IdtyConfirmedEvent { interface IdtyChangedOwnerKeyEvent { id: string; index: IdtyIndex; - account: Address; + accountId: Address; blockNumber: BlockNumber; } // a way to group data prepared for database insertion -interface PreparedData { +interface Data { accounts: Map<Address, Account>; identities: Map<IdtyIndex, Identity>; changeOwnerKey: ChangeOwnerKey[]; @@ -146,7 +147,7 @@ interface PreparedData { // ================================================================================ /// fill data with data collected from events -function getNewData(ctx: ProcessorContext<StoreWithCache>, ndata: NewData) { +function getNewData(ctx: Ctx, ndata: NewData) { const silence_events = [ events_t.system.extrinsicSuccess.name, events_t.system.killedAccount.name, @@ -213,7 +214,7 @@ function getNewData(ctx: ProcessorContext<StoreWithCache>, ndata: NewData) { ndata.identitiesCreated.push({ id: event.id, index: newI.idtyIndex, - account: ss58.codec(42).encode(newI.ownerKey), + accountId: ss58.codec(42).encode(newI.ownerKey), }); break; @@ -243,7 +244,7 @@ function getNewData(ctx: ProcessorContext<StoreWithCache>, ndata: NewData) { ndata.idtyChangedOwnerKey.push({ id: event.id, index: chok.idtyIndex, - account: ss58.codec(42).encode(chok.newOwnerKey), + accountId: ss58.codec(42).encode(chok.newOwnerKey), blockNumber: block.header.height, }); break; @@ -315,7 +316,7 @@ function getNewData(ctx: ProcessorContext<StoreWithCache>, ndata: NewData) { // ============================================================================================================= /// prepare data for injection into database -async function prepareData(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function prepareData(ctx: Ctx, newData: NewData, data: Data) { await createAccounts(ctx, newData, data); await createIdentities(ctx, newData, data); await confirmIdentities(ctx, newData, data); @@ -329,7 +330,7 @@ async function prepareData(ctx: ProcessorContext<StoreWithCache>, newData: NewDa // ============================================= /// store prepared data into database -async function storeData(ctx: ProcessorContext<StoreWithCache>, data: PreparedData) { +async function storeData(ctx: Ctx, data: Data) { // UPSERT = update or insert if not existing // account can have already existed, been killed, and recreated await ctx.store.upsert([...data.accounts.values()]); @@ -348,7 +349,7 @@ async function storeData(ctx: ProcessorContext<StoreWithCache>, data: PreparedDa // ============================================================================================================= -async function createAccounts(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function createAccounts(ctx: Ctx, newData: NewData, data: Data) { // system will tell when accounts are created (but this should be added above) for (let id of newData.accounts) { let newA = new Account({ id }); @@ -357,9 +358,20 @@ async function createAccounts(ctx: ProcessorContext<StoreWithCache>, newData: Ne } } -async function createIdentities(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function getOrCreateAccount(ctx: Ctx, data: Data, id: Address): Promise<Account> { + let account = data.accounts.get(id) ?? await ctx.store.get(Account, id); + if (account == null) { + // we need to create it + account = new Account({id}); + data.accounts.set(id, account); + } + return account; +} + +async function createIdentities(ctx: Ctx, newData: NewData, data: Data) { for (let i of newData.identitiesCreated) { - let account = await ctx.store.getOrFail(Account, i.account); + // an identity can be created for a non existing account without System.NewAccount event + let account = await getOrCreateAccount(ctx, data, i.accountId); let newI = new Identity({ id: i.id, index: i.index, @@ -370,19 +382,22 @@ async function createIdentities(ctx: ProcessorContext<StoreWithCache>, newData: } } -async function confirmIdentities(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function confirmIdentities(ctx: Ctx, newData: NewData, data: Data) { for (let i of newData.identitiesConfirmed) { - let idty = await ctx.store.findOneByOrFail(Identity, { index: i.index }); + // should never fail because identities can not be confirmed without have been created + let idty = data.identities.get(i.index) ?? await ctx.store.findOneByOrFail(Identity, { index: i.index }); idty.name = i.name; data.identities.set(i.index, idty); } } -async function changeIdtyOwnerKey(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function changeIdtyOwnerKey(ctx: Ctx, newData: NewData, data: Data) { for (let icok of newData.idtyChangedOwnerKey) { + // should never fail because change owner key is only available for existing identites let idty = await ctx.store.findOneOrFail(Identity, { where: { index: icok.index }, relations: { account: true } }); + // should never fail because old_account must pay fees to call change owner key let old_account = data.accounts.get(idty.account.id) ?? (await ctx.store.getOrFail(Account, idty.account.id)); - let new_account = data.accounts.get(icok.account) ?? (await ctx.store.getOrFail(Account, icok.account)); + let new_account = await getOrCreateAccount(ctx, data, icok.accountId); ctx.log.info(`changed owner key of idty ${idty.index} from ${old_account.id} to ${new_account.id}`); // actually change the account of the identity idty.account = new_account; @@ -400,10 +415,12 @@ async function changeIdtyOwnerKey(ctx: ProcessorContext<StoreWithCache>, newData } } -async function createTransfers(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function createTransfers(ctx: Ctx, newData: NewData, data: Data) { for (let t of newData.transfers) { let { id, blockNumber, timestamp, amount } = t; + // should never fail because source of transfer must be an existing account let from = data.accounts.get(t.from) ?? (await ctx.store.getOrFail(Account, t.from)); + // shoud never fail because destination of transfer must be existing account or raise System.NewAccount let to = data.accounts.get(t.to) ?? (await ctx.store.getOrFail(Account, t.to)); data.transfers.push( new Transfer({ @@ -418,15 +435,16 @@ async function createTransfers(ctx: ProcessorContext<StoreWithCache>, newData: N } } -async function createCerts(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function createCerts(ctx: Ctx, newData: NewData, data: Data) { for (let c of newData.certCreation) { let { id, issuerId, receiverId, createdOn, expireOn } = c; let cert = await ctx.store.findOne(Cert, { relations: { issuer: true, receiver: true }, where: { issuer: { index: issuerId }, receiver: { index: receiverId } }, }); + // first creation of the cert if (cert == null) { - // this is the first creation of the cert + // should never fail because cert issuer and receiver must be existing or created identities let issuer = data.identities.get(issuerId) ?? (await ctx.store.findOneByOrFail(Identity, { index: issuerId })); let receiver = data.identities.get(receiverId) ?? (await ctx.store.findOneByOrFail(Identity, { index: receiverId })); cert = new Cert({ @@ -437,9 +455,10 @@ async function createCerts(ctx: ProcessorContext<StoreWithCache>, newData: NewDa createdOn, expireOn, }); - } else { - // the cert has already existed, expired, and is created again - // we update it + } + // the cert has already existed, expired, and is created again + // we update it accordingly + else { cert.active = true; cert.createdOn = createdOn; cert.expireOn = expireOn; @@ -456,9 +475,11 @@ async function createCerts(ctx: ProcessorContext<StoreWithCache>, newData: NewDa } } -async function createCertRenewals(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function createCertRenewals(ctx: Ctx, newData: NewData, data: Data) { for (let c of newData.certRenewal) { let { id, issuerId, receiverId, blockNumber, expireOn } = c; + // should never fail because cert renewal can only happen on existing cert + // and can not be renewed at the same block as created (delay) let cert = await ctx.store.findOneOrFail(Cert, { relations: { issuer: true, receiver: true }, where: { issuer: { index: issuerId }, receiver: { index: receiverId } }, @@ -476,9 +497,11 @@ async function createCertRenewals(ctx: ProcessorContext<StoreWithCache>, newData } } -async function createCertRemovals(ctx: ProcessorContext<StoreWithCache>, newData: NewData, data: PreparedData) { +async function createCertRemovals(ctx: Ctx, newData: NewData, data: Data) { for (let c of newData.certRemoval) { let { id, issuerId, receiverId, blockNumber } = c; + // should never fail because cert removal can only happen on existing cert + // and cert should not be removed at their creation block let cert = await ctx.store.findOneOrFail(Cert, { relations: { issuer: true, receiver: true }, where: { issuer: { index: issuerId }, receiver: { index: receiverId } },