diff --git a/CHANGELOG.md b/CHANGELOG.md index 475847b..28391ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.5.0 + +- Updates mappings to process `NodeOperationalStatusMetadata` protobuf message. This metaprotocol message enables both storage/distribution workers & leads to set the operational status of the nodes. + # 1.4.4 diff --git a/db/migrations/1705406586630-Data.js b/db/migrations/1713200416940-Data.js similarity index 93% rename from db/migrations/1705406586630-Data.js rename to db/migrations/1713200416940-Data.js index d4a4225..078aec6 100644 --- a/db/migrations/1705406586630-Data.js +++ b/db/migrations/1713200416940-Data.js @@ -1,5 +1,5 @@ -module.exports = class Data1705406586630 { - name = 'Data1705406586630' +module.exports = class Data1713200416940 { + name = 'Data1713200416940' async up(db) { await db.query(`CREATE TABLE "next_entity_id" ("entity_name" character varying NOT NULL, "next_id" bigint NOT NULL, CONSTRAINT "PK_09a3b40db622a65096e7344d7ae" PRIMARY KEY ("entity_name"))`) @@ -10,7 +10,7 @@ module.exports = class Data1705406586630 { await db.query(`CREATE INDEX "IDX_aaf00b2c7d0cba49f97da14fbb" ON "storage_bucket_bag" ("bag_id") `) await db.query(`CREATE INDEX "IDX_4c475f6c9300284b095859eec3" ON "storage_bucket_bag" ("storage_bucket_id", "bag_id") `) await db.query(`CREATE TABLE "distribution_bucket_family" ("id" character varying NOT NULL, CONSTRAINT "PK_8cb7454d1ec34b0d3bb7ecdee4e" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "distribution_bucket_operator" ("id" character varying NOT NULL, "distribution_bucket_id" character varying, "worker_id" integer NOT NULL, "status" character varying(7) NOT NULL, CONSTRAINT "PK_03b87e6e972f414bab94c142285" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "distribution_bucket_operator" ("id" character varying NOT NULL, "distribution_bucket_id" character varying, "worker_id" numeric NOT NULL, "status" character varying(7) NOT NULL, CONSTRAINT "PK_03b87e6e972f414bab94c142285" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_678dc5427cdde0cd4fef2c07a4" ON "distribution_bucket_operator" ("distribution_bucket_id") `) await db.query(`CREATE TABLE "distribution_bucket" ("id" character varying NOT NULL, "family_id" character varying, "bucket_index" integer NOT NULL, "accepting_new_bags" boolean NOT NULL, "distributing" boolean NOT NULL, CONSTRAINT "PK_c90d25fff461f2f5fa9082e2fb7" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_8cb7454d1ec34b0d3bb7ecdee4" ON "distribution_bucket" ("family_id") `) @@ -22,12 +22,12 @@ module.exports = class Data1705406586630 { await db.query(`CREATE INDEX "IDX_ff8014300b8039dbaed764f51b" ON "storage_data_object" ("storage_bag_id") `) await db.query(`CREATE TABLE "video_subtitle" ("id" character varying NOT NULL, "mime_type" text NOT NULL, "asset_id" character varying, CONSTRAINT "PK_2ac3e585fc608e673e7fbf94d8e" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_b6eabfb8de4128b28d73681020" ON "video_subtitle" ("asset_id") `) - await db.query(`CREATE TABLE "storage_bucket_operator_metadata" ("id" character varying NOT NULL, "storage_bucket_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "extra" text, CONSTRAINT "StorageBucketOperatorMetadata_storageBucket" UNIQUE ("storage_bucket_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_7beffc9530b3f307bc1169cb52" UNIQUE ("storage_bucket_id"), CONSTRAINT "PK_9846a397400ae1a39b21fbd02d4" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "storage_bucket_operator_metadata" ("id" character varying NOT NULL, "storage_bucket_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "node_operational_status" jsonb, "extra" text, CONSTRAINT "StorageBucketOperatorMetadata_storageBucket" UNIQUE ("storage_bucket_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_7beffc9530b3f307bc1169cb52" UNIQUE ("storage_bucket_id"), CONSTRAINT "PK_9846a397400ae1a39b21fbd02d4" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_7beffc9530b3f307bc1169cb52" ON "storage_bucket_operator_metadata" ("storage_bucket_id") `) await db.query(`CREATE TABLE "distribution_bucket_family_metadata" ("id" character varying NOT NULL, "family_id" character varying NOT NULL, "region" text, "description" text, "areas" jsonb, "latency_test_targets" text array, CONSTRAINT "DistributionBucketFamilyMetadata_family" UNIQUE ("family_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_dd93ca0ea24f3e7a02f11c4c14" UNIQUE ("family_id"), CONSTRAINT "PK_df7a270835bb313d3ef17bdee2f" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_dd93ca0ea24f3e7a02f11c4c14" ON "distribution_bucket_family_metadata" ("family_id") `) await db.query(`CREATE INDEX "IDX_5510d3b244a63d6ec702faa426" ON "distribution_bucket_family_metadata" ("region") `) - await db.query(`CREATE TABLE "distribution_bucket_operator_metadata" ("id" character varying NOT NULL, "distirbution_bucket_operator_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "extra" text, CONSTRAINT "DistributionBucketOperatorMetadata_distirbutionBucketOperator" UNIQUE ("distirbution_bucket_operator_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_69ec9bdc975b95f7dff94a7106" UNIQUE ("distirbution_bucket_operator_id"), CONSTRAINT "PK_9bbecaa12f30e3826922688274f" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "distribution_bucket_operator_metadata" ("id" character varying NOT NULL, "distirbution_bucket_operator_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "node_operational_status" jsonb, "extra" text, CONSTRAINT "DistributionBucketOperatorMetadata_distirbutionBucketOperator" UNIQUE ("distirbution_bucket_operator_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_69ec9bdc975b95f7dff94a7106" UNIQUE ("distirbution_bucket_operator_id"), CONSTRAINT "PK_9bbecaa12f30e3826922688274f" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_69ec9bdc975b95f7dff94a7106" ON "distribution_bucket_operator_metadata" ("distirbution_bucket_operator_id") `) await db.query(`ALTER TABLE "storage_bucket_bag" ADD CONSTRAINT "FK_791e2f82e3919ffcef8712aa1b9" FOREIGN KEY ("storage_bucket_id") REFERENCES "storage_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) await db.query(`ALTER TABLE "storage_bucket_bag" ADD CONSTRAINT "FK_aaf00b2c7d0cba49f97da14fbba" FOREIGN KEY ("bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) diff --git a/generated/schema.graphql b/generated/schema.graphql index ccae9c0..6991db6 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -347,7 +347,7 @@ type DistributionBucketOperator { distributionBucket: DistributionBucket! """ID of the distribution group worker""" - workerId: Int! + workerId: BigInt! """Current operator status""" status: DistributionBucketOperatorStatus! @@ -373,6 +373,9 @@ type DistributionBucketOperatorMetadata { """Optional node location metadata""" nodeLocation: NodeLocationMetadata + """Optional node operational status""" + nodeOperationalStatus: NodeOperationalStatus + """Additional information about the node/operator""" extra: String } @@ -417,6 +420,26 @@ enum DistributionBucketOperatorMetadataOrderByInput { nodeLocation_city_DESC nodeLocation_city_ASC_NULLS_FIRST nodeLocation_city_DESC_NULLS_LAST + nodeOperationalStatus_rationale_ASC + nodeOperationalStatus_rationale_DESC + nodeOperationalStatus_rationale_ASC_NULLS_FIRST + nodeOperationalStatus_rationale_DESC_NULLS_LAST + nodeOperationalStatus_forced_ASC + nodeOperationalStatus_forced_DESC + nodeOperationalStatus_forced_ASC_NULLS_FIRST + nodeOperationalStatus_forced_DESC_NULLS_LAST + nodeOperationalStatus_from_ASC + nodeOperationalStatus_from_DESC + nodeOperationalStatus_from_ASC_NULLS_FIRST + nodeOperationalStatus_from_DESC_NULLS_LAST + nodeOperationalStatus_until_ASC + nodeOperationalStatus_until_DESC + nodeOperationalStatus_until_ASC_NULLS_FIRST + nodeOperationalStatus_until_DESC_NULLS_LAST + nodeOperationalStatus_isTypeOf_ASC + nodeOperationalStatus_isTypeOf_DESC + nodeOperationalStatus_isTypeOf_ASC_NULLS_FIRST + nodeOperationalStatus_isTypeOf_DESC_NULLS_LAST extra_ASC extra_DESC extra_ASC_NULLS_FIRST @@ -462,6 +485,8 @@ input DistributionBucketOperatorMetadataWhereInput { nodeEndpoint_not_endsWith: String nodeLocation_isNull: Boolean nodeLocation: NodeLocationMetadataWhereInput + nodeOperationalStatus_isNull: Boolean + nodeOperationalStatus: NodeOperationalStatusWhereInput extra_isNull: Boolean extra_eq: String extra_not_eq: String @@ -558,14 +583,14 @@ input DistributionBucketOperatorWhereInput { distributionBucket_isNull: Boolean distributionBucket: DistributionBucketWhereInput workerId_isNull: Boolean - workerId_eq: Int - workerId_not_eq: Int - workerId_gt: Int - workerId_gte: Int - workerId_lt: Int - workerId_lte: Int - workerId_in: [Int!] - workerId_not_in: [Int!] + workerId_eq: BigInt + workerId_not_eq: BigInt + workerId_gt: BigInt + workerId_gte: BigInt + workerId_lt: BigInt + workerId_lte: BigInt + workerId_in: [BigInt!] + workerId_not_in: [BigInt!] status_isNull: Boolean status_eq: DistributionBucketOperatorStatus status_not_eq: DistributionBucketOperatorStatus @@ -651,6 +676,14 @@ input DistributionBucketWhereInput { OR: [DistributionBucketWhereInput!] } +type DistributionNodeOperationalStatusSetEvent { + """Distribution bucket operator""" + bucketOperator: DistributionBucketOperator! + + """Operational status that was set""" + operationalStatus: NodeOperationalStatus! +} + type Event { """{blockNumber}-{indexInBlock}""" id: String! @@ -671,7 +704,7 @@ type Event { data: EventData! } -union EventData = MetaprotocolTransactionStatusEventData | DataObjectDeletedEventData +union EventData = MetaprotocolTransactionStatusEventData | DataObjectDeletedEventData | StorageNodeOperationalStatusSetEvent | DistributionNodeOperationalStatusSetEvent input EventDataWhereInput { result_isNull: Boolean @@ -693,6 +726,12 @@ input EventDataWhereInput { dataObjectId_not_startsWith: String dataObjectId_endsWith: String dataObjectId_not_endsWith: String + storageBucket_isNull: Boolean + storageBucket: StorageBucketWhereInput + operationalStatus_isNull: Boolean + operationalStatus: NodeOperationalStatusWhereInput + bucketOperator_isNull: Boolean + bucketOperator: DistributionBucketOperatorWhereInput isTypeOf_isNull: Boolean isTypeOf_eq: String isTypeOf_not_eq: String @@ -975,6 +1014,113 @@ input NodeLocationMetadataWhereInput { coordinates: GeoCoordinatesWhereInput } +union NodeOperationalStatus = NodeOperationalStatusNormal | NodeOperationalStatusNoService | NodeOperationalStatusNoServiceFrom | NodeOperationalStatusNoServiceUntil + +type NodeOperationalStatusNormal { + """Reason why node was set to this state""" + rationale: String +} + +type NodeOperationalStatusNoService { + """ + Whether the state was set by lead (true) or by the operator (false), it is + meant to prevent worker from unilaterally reversing. + """ + forced: Boolean! + + """Reason why node was set to this state""" + rationale: String +} + +type NodeOperationalStatusNoServiceFrom { + """ + Whether the state was set by lead (true) or by the operator (false), it is + meant to prevent worker from unilaterally reversing. + """ + forced: Boolean! + + """The time from which the bucket would have to no service""" + from: DateTime! + + """Reason why node was set to this state""" + rationale: String +} + +type NodeOperationalStatusNoServiceUntil { + """ + Whether the state was set by lead (true) or by the operator (false), it is + meant to prevent worker from unilaterally reversing. + """ + forced: Boolean! + + """The time from which the bucket would have to no service""" + from: DateTime! + + """The time until which the bucket would have to no service""" + until: DateTime! + + """Reason why node was set to this state""" + rationale: String +} + +input NodeOperationalStatusWhereInput { + rationale_isNull: Boolean + rationale_eq: String + rationale_not_eq: String + rationale_gt: String + rationale_gte: String + rationale_lt: String + rationale_lte: String + rationale_in: [String!] + rationale_not_in: [String!] + rationale_contains: String + rationale_not_contains: String + rationale_containsInsensitive: String + rationale_not_containsInsensitive: String + rationale_startsWith: String + rationale_not_startsWith: String + rationale_endsWith: String + rationale_not_endsWith: String + forced_isNull: Boolean + forced_eq: Boolean + forced_not_eq: Boolean + from_isNull: Boolean + from_eq: DateTime + from_not_eq: DateTime + from_gt: DateTime + from_gte: DateTime + from_lt: DateTime + from_lte: DateTime + from_in: [DateTime!] + from_not_in: [DateTime!] + until_isNull: Boolean + until_eq: DateTime + until_not_eq: DateTime + until_gt: DateTime + until_gte: DateTime + until_lt: DateTime + until_lte: DateTime + until_in: [DateTime!] + until_not_in: [DateTime!] + isTypeOf_isNull: Boolean + isTypeOf_eq: String + isTypeOf_not_eq: String + isTypeOf_gt: String + isTypeOf_gte: String + isTypeOf_lt: String + isTypeOf_lte: String + isTypeOf_in: [String!] + isTypeOf_not_in: [String!] + isTypeOf_contains: String + isTypeOf_not_contains: String + isTypeOf_containsInsensitive: String + isTypeOf_not_containsInsensitive: String + isTypeOf_startsWith: String + isTypeOf_not_startsWith: String + isTypeOf_endsWith: String + isTypeOf_not_endsWith: String +} + type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! @@ -1376,6 +1522,9 @@ type StorageBucketOperatorMetadata { """Optional node location metadata""" nodeLocation: NodeLocationMetadata + """Optional node operational status""" + nodeOperationalStatus: NodeOperationalStatus + """Additional information about the node/operator""" extra: String } @@ -1432,6 +1581,26 @@ enum StorageBucketOperatorMetadataOrderByInput { nodeLocation_city_DESC nodeLocation_city_ASC_NULLS_FIRST nodeLocation_city_DESC_NULLS_LAST + nodeOperationalStatus_rationale_ASC + nodeOperationalStatus_rationale_DESC + nodeOperationalStatus_rationale_ASC_NULLS_FIRST + nodeOperationalStatus_rationale_DESC_NULLS_LAST + nodeOperationalStatus_forced_ASC + nodeOperationalStatus_forced_DESC + nodeOperationalStatus_forced_ASC_NULLS_FIRST + nodeOperationalStatus_forced_DESC_NULLS_LAST + nodeOperationalStatus_from_ASC + nodeOperationalStatus_from_DESC + nodeOperationalStatus_from_ASC_NULLS_FIRST + nodeOperationalStatus_from_DESC_NULLS_LAST + nodeOperationalStatus_until_ASC + nodeOperationalStatus_until_DESC + nodeOperationalStatus_until_ASC_NULLS_FIRST + nodeOperationalStatus_until_DESC_NULLS_LAST + nodeOperationalStatus_isTypeOf_ASC + nodeOperationalStatus_isTypeOf_DESC + nodeOperationalStatus_isTypeOf_ASC_NULLS_FIRST + nodeOperationalStatus_isTypeOf_DESC_NULLS_LAST extra_ASC extra_DESC extra_ASC_NULLS_FIRST @@ -1477,6 +1646,8 @@ input StorageBucketOperatorMetadataWhereInput { nodeEndpoint_not_endsWith: String nodeLocation_isNull: Boolean nodeLocation: NodeLocationMetadataWhereInput + nodeOperationalStatus_isNull: Boolean + nodeOperationalStatus: NodeOperationalStatusWhereInput extra_isNull: Boolean extra_eq: String extra_not_eq: String @@ -1501,12 +1672,12 @@ input StorageBucketOperatorMetadataWhereInput { union StorageBucketOperatorStatus = StorageBucketOperatorStatusMissing | StorageBucketOperatorStatusInvited | StorageBucketOperatorStatusActive type StorageBucketOperatorStatusActive { - workerId: Int! + workerId: BigInt! transactorAccountId: String! } type StorageBucketOperatorStatusInvited { - workerId: Int! + workerId: BigInt! } type StorageBucketOperatorStatusMissing { @@ -1524,14 +1695,14 @@ input StorageBucketOperatorStatusWhereInput { phantom_in: [Int!] phantom_not_in: [Int!] workerId_isNull: Boolean - workerId_eq: Int - workerId_not_eq: Int - workerId_gt: Int - workerId_gte: Int - workerId_lt: Int - workerId_lte: Int - workerId_in: [Int!] - workerId_not_in: [Int!] + workerId_eq: BigInt + workerId_not_eq: BigInt + workerId_gt: BigInt + workerId_gte: BigInt + workerId_lt: BigInt + workerId_lte: BigInt + workerId_in: [BigInt!] + workerId_not_in: [BigInt!] transactorAccountId_isNull: Boolean transactorAccountId_eq: String transactorAccountId_not_eq: String @@ -1860,6 +2031,14 @@ input StorageDataObjectWhereInput { OR: [StorageDataObjectWhereInput!] } +type StorageNodeOperationalStatusSetEvent { + """Storage Bucket""" + storageBucket: StorageBucket! + + """Operational status that was set""" + operationalStatus: NodeOperationalStatus! +} + type VideoSubtitle { """(videoId)-{type}-{language}""" id: String! diff --git a/package-lock.json b/package-lock.json index c0a684b..77e4efa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "storage-squid", - "version": "1.4.4", + "version": "1.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "storage-squid", - "version": "1.4.4", + "version": "1.5.0", "hasInstallScript": true, "dependencies": { - "@joystream/js": "^1.4.0", + "@joystream/js": "^1.12.0", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "0.37.0", "@opentelemetry/core": "1.13.0", @@ -3361,13 +3361,13 @@ "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" }, "node_modules/@joystream/js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@joystream/js/-/js-1.4.0.tgz", - "integrity": "sha512-kEiKPIhsuk4B2vteAZoFYoZ+slyAiDXu1hDKMBddt1AKWfD1qxrHKAuF2cBkQIN4KpeNEJrRK9vy8G3glvaDvQ==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@joystream/js/-/js-1.12.0.tgz", + "integrity": "sha512-aRDP1PEcQDU5lNaxHt501/P5LKfgB8VfD4dsjdaDYruls8wQFIg6/EEctjn0bT4HxY14EKK27hrQX00Nu1Ip/A==", "dependencies": { - "@joystream/metadata-protobuf": "^2.8.1", - "@joystream/types": "^2.0.0", - "@polkadot/util-crypto": "9.5.1", + "@joystream/metadata-protobuf": "^2.16.0", + "@joystream/types": "^4.4.0", + "@polkadot/util-crypto": "^12.6.2", "axios": "^1.2.1", "buffer": "^6.0.3", "lodash": "^4.17.21", @@ -3376,7 +3376,7 @@ "protobufjs": "^6.11.3" }, "engines": { - "node": ">=14.0.0", + "node": ">=14.18.0", "yarn": "^1.22.15" } }, @@ -3386,9 +3386,9 @@ "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" }, "node_modules/@joystream/metadata-protobuf": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@joystream/metadata-protobuf/-/metadata-protobuf-2.8.1.tgz", - "integrity": "sha512-ckxvQP3RC8gKCJWU1xpXosxEfgFcChgaIncy06AZfn50x6+9mFEsxQTTogN7b1g1T026oSFYZMDq52tkBw2Zew==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@joystream/metadata-protobuf/-/metadata-protobuf-2.16.0.tgz", + "integrity": "sha512-I5xg0Ko4fWPWFAQlA/QocAd7KXKdGxD4bIWc1dWxrKzxhlCe4zk6/iujGY2pH+2Nhtr5GjcKSmNoZ0/Cih9PXw==", "dependencies": { "@types/iso-3166-2": "^1.0.0", "@types/long": "^4.0.1", @@ -7338,9 +7338,9 @@ } }, "node_modules/@types/iso-3166-2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/iso-3166-2/-/iso-3166-2-1.0.0.tgz", - "integrity": "sha512-DYDyoRyPyxBeI9bYoTXLfsOZH12m1anrWEj9LU5Sl9rgsJ4soJMYf/7byozM+64Smn6/a1i079eQLGuPykwaHQ==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/iso-3166-2/-/iso-3166-2-1.0.3.tgz", + "integrity": "sha512-jOqKFSfZYVJ5ARkXH2V2RrEhLvFds1RVrFGRKKxqLU3jjExlf5LtqdFgXNd19KAMRhgsZSNjedeLDVYlGUemZg==" }, "node_modules/@types/js-yaml": { "version": "4.0.5", @@ -14492,9 +14492,9 @@ } }, "node_modules/protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -19220,11 +19220,11 @@ "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" }, "@joystream/js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@joystream/js/-/js-1.4.0.tgz", - "integrity": "sha512-kEiKPIhsuk4B2vteAZoFYoZ+slyAiDXu1hDKMBddt1AKWfD1qxrHKAuF2cBkQIN4KpeNEJrRK9vy8G3glvaDvQ==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@joystream/js/-/js-1.12.0.tgz", + "integrity": "sha512-aRDP1PEcQDU5lNaxHt501/P5LKfgB8VfD4dsjdaDYruls8wQFIg6/EEctjn0bT4HxY14EKK27hrQX00Nu1Ip/A==", "requires": { - "@joystream/metadata-protobuf": "^2.8.1", + "@joystream/metadata-protobuf": "^2.16.0", "@joystream/types": "0.20.5", "@polkadot/util-crypto": "9.5.1", "axios": "^1.2.1", @@ -19243,9 +19243,9 @@ } }, "@joystream/metadata-protobuf": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@joystream/metadata-protobuf/-/metadata-protobuf-2.8.1.tgz", - "integrity": "sha512-ckxvQP3RC8gKCJWU1xpXosxEfgFcChgaIncy06AZfn50x6+9mFEsxQTTogN7b1g1T026oSFYZMDq52tkBw2Zew==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@joystream/metadata-protobuf/-/metadata-protobuf-2.16.0.tgz", + "integrity": "sha512-I5xg0Ko4fWPWFAQlA/QocAd7KXKdGxD4bIWc1dWxrKzxhlCe4zk6/iujGY2pH+2Nhtr5GjcKSmNoZ0/Cih9PXw==", "requires": { "@types/iso-3166-2": "^1.0.0", "@types/long": "^4.0.1", @@ -22253,9 +22253,9 @@ } }, "@types/iso-3166-2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/iso-3166-2/-/iso-3166-2-1.0.0.tgz", - "integrity": "sha512-DYDyoRyPyxBeI9bYoTXLfsOZH12m1anrWEj9LU5Sl9rgsJ4soJMYf/7byozM+64Smn6/a1i079eQLGuPykwaHQ==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/iso-3166-2/-/iso-3166-2-1.0.3.tgz", + "integrity": "sha512-jOqKFSfZYVJ5ARkXH2V2RrEhLvFds1RVrFGRKKxqLU3jjExlf5LtqdFgXNd19KAMRhgsZSNjedeLDVYlGUemZg==" }, "@types/js-yaml": { "version": "4.0.5", @@ -27577,9 +27577,9 @@ "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==" }, "protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", diff --git a/package.json b/package.json index f9e15fd..7889cad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storage-squid", - "version": "1.4.4", + "version": "1.5.0", "engines": { "node": ">=16" }, @@ -26,7 +26,7 @@ "@joystream/types": "0.20.5" }, "dependencies": { - "@joystream/js": "^1.4.0", + "@joystream/js": "^1.12.0", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "0.37.0", "@opentelemetry/core": "1.13.0", diff --git a/schema/events.graphql b/schema/events.graphql index 61ee217..84a4ec9 100644 --- a/schema/events.graphql +++ b/schema/events.graphql @@ -18,7 +18,11 @@ type Event @entity { data: EventData! } -union EventData = MetaprotocolTransactionStatusEventData | DataObjectDeletedEventData +union EventData = + MetaprotocolTransactionStatusEventData + | DataObjectDeletedEventData + | StorageNodeOperationalStatusSetEvent + | DistributionNodeOperationalStatusSetEvent type MetaprotocolTransactionResultOK { phantom: Int @@ -41,3 +45,19 @@ type DataObjectDeletedEventData { "Runtime ID of deleted the deleted object" dataObjectId: ID! } + +type StorageNodeOperationalStatusSetEvent { + "Storage Bucket" + storageBucket: StorageBucket! + + "Operational status that was set" + operationalStatus: NodeOperationalStatus! +} + +type DistributionNodeOperationalStatusSetEvent { + "Distribution bucket operator" + bucketOperator: DistributionBucketOperator! + + "Operational status that was set" + operationalStatus: NodeOperationalStatus! +} diff --git a/schema/storage.graphql b/schema/storage.graphql index ec0ffb2..64dad14 100644 --- a/schema/storage.graphql +++ b/schema/storage.graphql @@ -3,11 +3,11 @@ type StorageBucketOperatorStatusMissing { } type StorageBucketOperatorStatusInvited { - workerId: Int! + workerId: BigInt! } type StorageBucketOperatorStatusActive { - workerId: Int! + workerId: BigInt! transactorAccountId: String! } @@ -62,6 +62,50 @@ type NodeLocationMetadata { coordinates: GeoCoordinates } +type NodeOperationalStatusNormal { + "Reason why node was set to this state" + rationale: String +} + +type NodeOperationalStatusNoService { + "Whether the state was set by lead (true) or by the operator (false), it is meant to prevent worker from unilaterally reversing." + forced: Boolean! + + "Reason why node was set to this state" + rationale: String +} + +type NodeOperationalStatusNoServiceFrom { + "Whether the state was set by lead (true) or by the operator (false), it is meant to prevent worker from unilaterally reversing." + forced: Boolean! + + "The time from which the bucket would have to no service" + from: DateTime! + + "Reason why node was set to this state" + rationale: String +} + +type NodeOperationalStatusNoServiceUntil { + "Whether the state was set by lead (true) or by the operator (false), it is meant to prevent worker from unilaterally reversing." + forced: Boolean! + + "The time from which the bucket would have to no service" + from: DateTime! + + "The time until which the bucket would have to no service" + until: DateTime! + + "Reason why node was set to this state" + rationale: String +} + +union NodeOperationalStatus = + NodeOperationalStatusNormal + | NodeOperationalStatusNoService + | NodeOperationalStatusNoServiceFrom + | NodeOperationalStatusNoServiceUntil + type StorageBucketOperatorMetadata @entity { id: ID! @@ -74,6 +118,9 @@ type StorageBucketOperatorMetadata @entity { "Optional node location metadata" nodeLocation: NodeLocationMetadata + "Optional node operational status" + nodeOperationalStatus: NodeOperationalStatus + "Additional information about the node/operator" extra: String } @@ -233,6 +280,9 @@ type DistributionBucketOperatorMetadata @entity { "Optional node location metadata" nodeLocation: NodeLocationMetadata + "Optional node operational status" + nodeOperationalStatus: NodeOperationalStatus + "Additional information about the node/operator" extra: String } @@ -250,7 +300,7 @@ type DistributionBucketOperator @entity { distributionBucket: DistributionBucket! "ID of the distribution group worker" - workerId: Int! + workerId: BigInt! "Current operator status" status: DistributionBucketOperatorStatus! diff --git a/src/mappings/storage/index.ts b/src/mappings/storage/index.ts index 7d56dc1..0ae6cc7 100644 --- a/src/mappings/storage/index.ts +++ b/src/mappings/storage/index.ts @@ -60,7 +60,7 @@ export async function processStorageBucketCreatedEvent({ }) if (invitedWorkerId !== undefined) { storageBucket.operatorStatus = new StorageBucketOperatorStatusInvited({ - workerId: Number(invitedWorkerId), + workerId: invitedWorkerId, }) } else { storageBucket.operatorStatus = new StorageBucketOperatorStatusMissing() @@ -101,7 +101,7 @@ export async function processStorageBucketInvitationAcceptedEvent({ .getRepository(StorageBucket) .getByIdOrFail(bucketId.toString()) storageBucket.operatorStatus = new StorageBucketOperatorStatusActive({ - workerId: Number(workerId), + workerId, transactorAccountId: toAddress(hexToU8a(transactorAccountId)), }) } @@ -129,7 +129,7 @@ export async function processStorageBucketOperatorInvitedEvent({ .getRepository(StorageBucket) .getByIdOrFail(bucketId.toString()) storageBucket.operatorStatus = new StorageBucketOperatorStatusInvited({ - workerId: Number(workerId), + workerId, }) } @@ -482,7 +482,7 @@ export function processDistributionBucketOperatorInvitedEvent({ id: distributionOperatorId(bucketId, workerId), distributionBucketId: distributionBucketId(bucketId), status: DistributionBucketOperatorStatus.INVITED, - workerId: Number(workerId), + workerId, }) } diff --git a/src/mappings/storage/metadata.ts b/src/mappings/storage/metadata.ts index acbb7c6..dd349eb 100644 --- a/src/mappings/storage/metadata.ts +++ b/src/mappings/storage/metadata.ts @@ -4,7 +4,10 @@ import { IDistributionBucketOperatorMetadata, IGeographicalArea, INodeLocationMetadata, + INodeOperationalStatus, IStorageBucketOperatorMetadata, + NodeOperationalStatusNoServiceFrom as NodeOperationalStatusNoServiceFromMetadata, + NodeOperationalStatusNoServiceUntil as NodeOperationalStatusNoServiceUntilMetadata, } from '@joystream/metadata-protobuf' import { DecodedMetadataObject } from '@joystream/metadata-protobuf/types' import { @@ -13,22 +16,27 @@ import { isValidCountryCode, isValidSubdivisionCode, } from '@joystream/metadata-protobuf/utils' +import _ from 'lodash' +import { Logger } from '../../logger' import { - StorageBucketOperatorMetadata, - NodeLocationMetadata, - GeoCoordinates, + Continent, DistributionBucketFamilyMetadata, + DistributionBucketOperatorMetadata, + GeoCoordinates, + GeographicalArea, GeographicalAreaContinent, - Continent, GeographicalAreaCountry, GeographicalAreaSubdivistion, - DistributionBucketOperatorMetadata, - GeographicalArea, + NodeLocationMetadata, + NodeOperationalStatus, + NodeOperationalStatusNoService, + NodeOperationalStatusNoServiceFrom, + NodeOperationalStatusNoServiceUntil, + NodeOperationalStatusNormal, + StorageBucketOperatorMetadata, } from '../../model' -import { invalidMetadata } from '../utils' import { EntityManagerOverlay, Flat } from '../../utils/overlay' -import { Logger } from '../../logger' -import _ from 'lodash' +import { invalidMetadata, parseDateStr } from '../utils' export const protobufContinentToGraphlContinent: { [key in GeographicalAreaProto.Continent]: Continent @@ -60,6 +68,13 @@ export async function processStorageOperatorMetadata( if (isSet(metadataUpdate.location)) { processNodeLocationMetadata(operatorMetadata, metadataUpdate.location) } + if (isSet(metadataUpdate.operationalStatus)) { + operatorMetadata.nodeOperationalStatus = processNodeOperationalStatusMetadata( + 'worker', + operatorMetadata.nodeOperationalStatus, + metadataUpdate.operationalStatus + ) + } if (isSet(metadataUpdate.extra)) { operatorMetadata.extra = metadataUpdate.extra || null } @@ -103,6 +118,79 @@ function processNodeLocationMetadata( } } +export function processNodeOperationalStatusMetadata( + actorContext: 'lead' | 'worker', + currentStatus: NodeOperationalStatus | null | undefined, + meta: INodeOperationalStatus +): NodeOperationalStatus | null | undefined { + const isCurrentStatusForced = + currentStatus && + (currentStatus instanceof NodeOperationalStatusNoService || + currentStatus instanceof NodeOperationalStatusNoServiceFrom || + currentStatus instanceof NodeOperationalStatusNoServiceUntil) && + currentStatus.forced + + // if current state is forced by lead, then prevent worker from unilaterally reversing. + if (isCurrentStatusForced && actorContext === 'worker') { + return currentStatus + } + + // For status type Normal + if (meta.normal) { + const status = new NodeOperationalStatusNormal() + status.rationale = meta.normal.rationale + return status + } + // For status type NoService + else if (meta.noService) { + const status = new NodeOperationalStatusNoService() + status.rationale = meta.noService.rationale + status.forced = actorContext === 'lead' + return status + } + // For status type NoServiceFrom + else if (meta.noServiceFrom) { + const from = parseDateStr(meta.noServiceFrom.from) + + // Date must be in the future + if (!from || from < new Date()) { + invalidMetadata( + NodeOperationalStatusNoServiceFromMetadata, + `Invalid date for "noServiceFrom"`, + { decodedMessage: meta.noServiceFrom } + ) + return currentStatus + } + + const status = new NodeOperationalStatusNoServiceFrom() + status.rationale = meta.noServiceFrom.rationale + status.forced = actorContext === 'lead' + status.from = from + return status + } + // For status type NoServiceUntil + else if (meta.noServiceUntil) { + const from = meta.noServiceUntil.from ? parseDateStr(meta.noServiceUntil.from) : new Date() + const until = parseDateStr(meta.noServiceUntil.until) + + // Dates must be in the future and "until" must be after "from" + if (!from || !until || from < new Date() || from > until) { + invalidMetadata( + NodeOperationalStatusNoServiceUntilMetadata, + `Invalid date/s for "noServiceUntil"`, + { decodedMessage: meta.noServiceUntil } + ) + return currentStatus + } + const status = new NodeOperationalStatusNoServiceUntil() + status.rationale = meta.noServiceUntil.rationale + status.forced = actorContext === 'lead' + status.from = from + status.until = until + return status + } +} + export async function processDistributionOperatorMetadata( overlay: EntityManagerOverlay, operatorId: string, @@ -121,6 +209,13 @@ export async function processDistributionOperatorMetadata( if (isSet(metadataUpdate.location)) { processNodeLocationMetadata(operatorMetadata, metadataUpdate.location) } + if (isSet(metadataUpdate.operationalStatus)) { + operatorMetadata.nodeOperationalStatus = processNodeOperationalStatusMetadata( + 'worker', + operatorMetadata.nodeOperationalStatus, + metadataUpdate.operationalStatus + ) + } if (isSet(metadataUpdate.extra)) { operatorMetadata.extra = metadataUpdate.extra || null } diff --git a/src/mappings/storage/utils.ts b/src/mappings/storage/utils.ts index 61983d8..67d7f35 100644 --- a/src/mappings/storage/utils.ts +++ b/src/mappings/storage/utils.ts @@ -1,8 +1,11 @@ +import { ISetNodeOperationalStatus, SetNodeOperationalStatus } from '@joystream/metadata-protobuf' +import { isSet } from '@joystream/metadata-protobuf/utils' import { hexToString } from '@polkadot/util' import { DataObjectDeletedEventData, DistributionBucketOperator, DistributionBucketOperatorMetadata, + DistributionNodeOperationalStatusSetEvent, Event, StorageBag, StorageBagOwner, @@ -10,7 +13,10 @@ import { StorageBagOwnerCouncil, StorageBagOwnerMember, StorageBagOwnerWorkingGroup, + StorageBucket, + StorageBucketOperatorMetadata, StorageDataObject, + StorageNodeOperationalStatusSetEvent, VideoSubtitle, } from '../../model' import { Block } from '../../processor' @@ -23,7 +29,8 @@ import { } from '../../types/v1000' import { criticalError } from '../../utils/misc' import { EntityManagerOverlay, Flat, RepositoryOverlay } from '../../utils/overlay' -import { genericEventFields } from '../utils' +import { genericEventFields, invalidMetadata } from '../utils' +import { processNodeOperationalStatusMetadata } from './metadata' export function getDynamicBagId(bagId: DynamicBagIdType): string { if (bagId.__kind === 'Channel') { @@ -206,3 +213,125 @@ export async function deleteDataObjectsByIds( subtitlesRepository.remove(...currentSubtitles.flat()) await deleteDataObjects(overlay, block, indexInBlock, extrinsicHash, objects) } + +export async function processSetNodeOperationalStatusMessage( + overlay: EntityManagerOverlay, + block: Block, + indexInBlock: number, + extrinsicHash: string | undefined, + workingGroup: 'storageWorkingGroup' | 'distributionWorkingGroup', + runtimeWorkerId: bigint | undefined, // ID of the worker who sent the message, undefined if it's the Lead + meta: ISetNodeOperationalStatus +): Promise { + const bucketId = meta.bucketId || '' + + // Update the operational status of Storage node + if (workingGroup === 'storageWorkingGroup') { + const storageBucket = await overlay.getRepository(StorageBucket).getById(bucketId) + if (!storageBucket) { + return invalidMetadata( + SetNodeOperationalStatus, + `The storage bucket ${bucketId} does not exist` + ) + } else if (storageBucket.operatorStatus.isTypeOf !== 'StorageBucketOperatorStatusActive') { + return invalidMetadata( + SetNodeOperationalStatus, + `The storage bucket ${bucketId} is not active` + ) + // If the actor is a worker, check if the worker is the operator of the storage bucket + } else if (runtimeWorkerId && storageBucket.operatorStatus.workerId !== runtimeWorkerId) { + return invalidMetadata( + SetNodeOperationalStatus, + `The worker ${runtimeWorkerId} is not the operator of the storage bucket ${bucketId}` + ) + } + + // create metadata entity if it does not exist already + const metadataEntity = + (await overlay.getRepository(StorageBucketOperatorMetadata).getById(bucketId)) || + overlay + .getRepository(StorageBucketOperatorMetadata) + .new({ id: bucketId, storageBucketId: bucketId }) + + if (isSet(meta.operationalStatus)) { + const currentNodeOperationalStatusType = metadataEntity.nodeOperationalStatus?.isTypeOf + + metadataEntity.nodeOperationalStatus = processNodeOperationalStatusMetadata( + runtimeWorkerId ? 'worker' : 'lead', + metadataEntity.nodeOperationalStatus, + meta.operationalStatus + ) + + // event processing + + if (currentNodeOperationalStatusType !== metadataEntity.nodeOperationalStatus?.isTypeOf) { + const operationalStatusSetEvent = new StorageNodeOperationalStatusSetEvent({ + ...genericEventFields(overlay, block, indexInBlock, extrinsicHash), + storageBucket: storageBucket.id, + operationalStatus: metadataEntity.nodeOperationalStatus || undefined, + }) + + overlay.getRepository(Event).new({ + ...genericEventFields(overlay, block, indexInBlock, extrinsicHash), + data: operationalStatusSetEvent, + }) + } + } + } + + // Update the operational status of Distribution node + if (workingGroup === 'distributionWorkingGroup') { + const workerId = runtimeWorkerId ? runtimeWorkerId.toString() : meta.workerId || '' + const distributionOperatorId = `${bucketId}-${workerId}` + const operator = await overlay + .getRepository(DistributionBucketOperator) + .getById(distributionOperatorId) + + if (!operator) { + return invalidMetadata( + SetNodeOperationalStatus, + `The distribution bucket operator ${distributionOperatorId} does not exist` + ) + } else if (runtimeWorkerId && operator.workerId !== runtimeWorkerId) { + return invalidMetadata( + SetNodeOperationalStatus, + `The worker ${runtimeWorkerId} is not the operator of the distribution bucket ${bucketId}` + ) + } + + // create metadata entity if it does not exist already + const metadataEntity = + (await overlay + .getRepository(DistributionBucketOperatorMetadata) + .getById(distributionOperatorId)) || + overlay.getRepository(DistributionBucketOperatorMetadata).new({ + id: distributionOperatorId, + distirbutionBucketOperatorId: distributionOperatorId, + }) + + if (isSet(meta.operationalStatus)) { + const currentNodeOperationalStatusType = metadataEntity.nodeOperationalStatus?.isTypeOf + + metadataEntity.nodeOperationalStatus = processNodeOperationalStatusMetadata( + runtimeWorkerId ? 'worker' : 'lead', + metadataEntity.nodeOperationalStatus, + meta.operationalStatus + ) + + // event processing + + if (currentNodeOperationalStatusType !== metadataEntity.nodeOperationalStatus?.isTypeOf) { + const operationalStatusSetEvent = new DistributionNodeOperationalStatusSetEvent({ + ...genericEventFields(overlay, block, indexInBlock, extrinsicHash), + bucketOperator: operator.id, + operationalStatus: metadataEntity.nodeOperationalStatus || undefined, + }) + + overlay.getRepository(Event).new({ + ...genericEventFields(overlay, block, indexInBlock, extrinsicHash), + data: operationalStatusSetEvent, + }) + } + } + } +} diff --git a/src/mappings/utils.ts b/src/mappings/utils.ts index 738bbd0..3435df3 100644 --- a/src/mappings/utils.ts +++ b/src/mappings/utils.ts @@ -104,3 +104,20 @@ export function backwardCompatibleMetaID(block: Block, indexInBlock: number) { export function u8aToBytes(array?: Uint8Array | null): Bytes { return createType('Bytes', array ? u8aToHex(array) : '') } + +export function toLowerFirstLetter(str: string) { + if (!str) return '' // Return an empty string if str is falsy + return str.charAt(0).toLowerCase() + str.slice(1) +} + +export function parseDateStr(date: string): Date | undefined { + try { + if (date) { + const dateObj = new Date(date) + dateObj.toISOString() // Throws an error if the date is invalid + return dateObj + } + } catch (error) { + console.error(`Invalid date format:`, date) + } +} diff --git a/src/mappings/workingGroups/index.ts b/src/mappings/workingGroups/index.ts new file mode 100644 index 0000000..c8008c7 --- /dev/null +++ b/src/mappings/workingGroups/index.ts @@ -0,0 +1,85 @@ +import { RemarkMetadataAction } from '@joystream/metadata-protobuf' +import { Block, EventHandlerContext } from '../../processor' +import { EntityManagerOverlay } from '../../utils/overlay' +import { processSetNodeOperationalStatusMessage } from '../storage/utils' +import { deserializeMetadataStr, invalidMetadata, toLowerFirstLetter } from '../utils' + +export async function processWorkingGroupsLeadRemarkedEvent({ + overlay, + block, + event, + indexInBlock, + extrinsicHash, + eventDecoder, +}: EventHandlerContext< + 'StorageWorkingGroup.LeadRemarked' | 'DistributionWorkingGroup.LeadRemarked' +>) { + const [metadataBytes] = eventDecoder.v1000.decode(event) + + // Get the working group name + const [workingGroup] = event.name.split('.') + const workingGroupName = toLowerFirstLetter(workingGroup) + + await applyWorkingGroupsRemark( + overlay, + block, + indexInBlock, + extrinsicHash, + workingGroupName as 'storageWorkingGroup' | 'distributionWorkingGroup', + undefined, + metadataBytes + ) +} + +export async function processWorkingGroupsWorkerRemarkedEvent({ + overlay, + block, + event, + indexInBlock, + extrinsicHash, + eventDecoder, +}: EventHandlerContext< + 'StorageWorkingGroup.WorkerRemarked' | 'DistributionWorkingGroup.WorkerRemarked' +>) { + const [workerId, metadataBytes] = eventDecoder.v1000.decode(event) + + // Get the working group name + const [workingGroup] = event.name.split('.') + const workingGroupName = toLowerFirstLetter(workingGroup) + + await applyWorkingGroupsRemark( + overlay, + block, + indexInBlock, + extrinsicHash, + workingGroupName as 'storageWorkingGroup' | 'distributionWorkingGroup', + workerId, + metadataBytes + ) +} + +async function applyWorkingGroupsRemark( + overlay: EntityManagerOverlay, + block: Block, + indexInBlock: number, + extrinsicHash: string | undefined, + workingGroup: 'storageWorkingGroup' | 'distributionWorkingGroup', + workerId: bigint | undefined, + metadataBytes: string +): Promise { + const metadata = deserializeMetadataStr(RemarkMetadataAction, metadataBytes) + + if (metadata?.setNodeOperationalStatus) { + await processSetNodeOperationalStatusMessage( + overlay, + block, + indexInBlock, + extrinsicHash, + workingGroup, + workerId, + metadata.setNodeOperationalStatus + ) + } else { + return invalidMetadata(RemarkMetadataAction, 'Unsupported remarked action') + } +} diff --git a/src/processor.ts b/src/processor.ts index b9ad307..7fa215e 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -40,6 +40,10 @@ import { processStorageOperatorMetadataSetEvent, processVoucherChangedEvent, } from './mappings/storage' +import { + processWorkingGroupsLeadRemarkedEvent, + processWorkingGroupsWorkerRemarkedEvent, +} from './mappings/workingGroups' import { events } from './types' import { EntityManagerOverlay } from './utils/overlay' @@ -57,7 +61,10 @@ type MapModuleEvents = { string as `${Capitalize}.${Capitalize}`]: typeof events[Module][Event] } -type EventsMap = MapModuleEvents<'content'> & MapModuleEvents<'storage'> +type EventsMap = MapModuleEvents<'content'> & + MapModuleEvents<'storage'> & + MapModuleEvents<'storageWorkingGroup'> & + MapModuleEvents<'distributionWorkingGroup'> type EventNames = keyof EventsMap export type EventHandlerContext = { @@ -110,6 +117,10 @@ const eventHandlers: EventHandlers = { 'Storage.DistributionBucketFamilyCreated': processDistributionBucketFamilyCreatedEvent, 'Storage.DistributionBucketFamilyMetadataSet': processDistributionBucketFamilyMetadataSetEvent, 'Storage.DistributionBucketFamilyDeleted': processDistributionBucketFamilyDeletedEvent, + 'StorageWorkingGroup.LeadRemarked': processWorkingGroupsLeadRemarkedEvent, + 'StorageWorkingGroup.WorkerRemarked': processWorkingGroupsWorkerRemarkedEvent, + 'DistributionWorkingGroup.LeadRemarked': processWorkingGroupsLeadRemarkedEvent, + 'DistributionWorkingGroup.WorkerRemarked': processWorkingGroupsWorkerRemarkedEvent, } const eventNames = Object.keys(eventHandlers) diff --git a/typegen.json b/typegen.json index a67a894..0db14fd 100644 --- a/typegen.json +++ b/typegen.json @@ -38,9 +38,13 @@ "DistributionBucketFamilyCreated", "DistributionBucketFamilyMetadataSet", "DistributionBucketFamilyDeleted" - ], - "calls": [], - "storage": [] + ] + }, + "StorageWorkingGroup": { + "events": ["WorkerRemarked", "LeadRemarked"] + }, + "DistributionWorkingGroup": { + "events": ["WorkerRemarked", "LeadRemarked"] } } }