Skip to content
Snippets Groups Projects
Commit e661667d authored by Hugo Trentesaux's avatar Hugo Trentesaux
Browse files

fix identity creation on non existing account

ctx type alias

fix account creation bug

rename prepared data

add never fail comments
parent 20befebc
Branches
Tags
No related merge requests found
# 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
......@@ -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
// 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 } },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment