diff --git a/subgraph/abi/FilecoinWarmStorageServiceLegacy.abi.json b/subgraph/abi/FilecoinWarmStorageServiceLegacy.abi.json new file mode 100644 index 00000000..986ab3dd --- /dev/null +++ b/subgraph/abi/FilecoinWarmStorageServiceLegacy.abi.json @@ -0,0 +1,33 @@ +[ + { + "type": "event", + "name": "PieceAdded", + "inputs": [ + { + "name": "dataSetId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "pieceId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "keys", + "type": "string[]", + "indexed": false, + "internalType": "string[]" + }, + { + "name": "values", + "type": "string[]", + "indexed": false, + "internalType": "string[]" + } + ], + "anonymous": false + } +] \ No newline at end of file diff --git a/subgraph/abis/FilecoinWarmStorageService.json b/subgraph/abis/FilecoinWarmStorageService.json deleted file mode 100644 index 2685e26d..00000000 --- a/subgraph/abis/FilecoinWarmStorageService.json +++ /dev/null @@ -1,129 +0,0 @@ -[ - { - "type": "event", - "name": "DataSetCreated", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "pdpRailId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "cacheMissRailId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "cdnRailId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "payer", "type": "address", "indexed": false, "internalType": "address" }, - { "name": "serviceProvider", "type": "address", "indexed": false, "internalType": "address" }, - { "name": "payee", "type": "address", "indexed": false, "internalType": "address" }, - { "name": "metadataKeys", "type": "string[]", "indexed": false, "internalType": "string[]" }, - { "name": "metadataValues", "type": "string[]", "indexed": false, "internalType": "string[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RailRateUpdated", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "railId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "newRate", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "FaultRecord", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "periodsFaulted", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "deadline", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProviderApproved", - "inputs": [{ "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }], - "anonymous": false - }, - { - "type": "event", - "name": "ProviderUnapproved", - "inputs": [{ "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }], - "anonymous": false - }, - { - "type": "event", - "name": "PieceAdded", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "pieceId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "keys", "type": "string[]", "indexed": false, "internalType": "string[]" }, - { "name": "values", "type": "string[]", "indexed": false, "internalType": "string[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PieceAdded", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "pieceId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { - "name": "pieceCid", - "type": "tuple", - "indexed": false, - "internalType": "struct Cids.Cid", - "components": [ - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { "name": "keys", "type": "string[]", "indexed": false, "internalType": "string[]" }, - { "name": "values", "type": "string[]", "indexed": false, "internalType": "string[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PDPPaymentTerminated", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "endEpoch", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "pdpRailId", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "CDNPaymentTerminated", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "endEpoch", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "cacheMissRailId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "cdnRailId", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PaymentArbitrated", - "inputs": [ - { "name": "railId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "dataSetId", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "originalAmount", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "modifiedAmount", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "faultedEpochs", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "DataSetServiceProviderChanged", - "inputs": [ - { "name": "dataSetId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "oldServiceProvider", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "newServiceProvider", "type": "address", "indexed": true, "internalType": "address" } - ], - "anonymous": false - } -] diff --git a/subgraph/abis/PDPVerifier.json b/subgraph/abis/PDPVerifier.json deleted file mode 100644 index 5bbd5e72..00000000 --- a/subgraph/abis/PDPVerifier.json +++ /dev/null @@ -1,97 +0,0 @@ -[ - { - "type": "function", - "name": "getRandomness", - "inputs": [{ "name": "epoch", "type": "uint256", "internalType": "uint256" }], - "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getPieceCid", - "inputs": [ - { "name": "setId", "type": "uint256", "internalType": "uint256" }, - { "name": "pieceId", "type": "uint256", "internalType": "uint256" } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct Cids.Cid", - "components": [{ "name": "data", "type": "bytes", "internalType": "bytes" }] - } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "StorageProviderChanged", - "inputs": [ - { "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "oldStorageProvider", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "newStorageProvider", "type": "address", "indexed": true, "internalType": "address" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "DataSetDeleted", - "inputs": [ - { "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "deletedLeafCount", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "NextProvingPeriod", - "inputs": [ - { "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "challengeEpoch", "type": "uint256", "indexed": false, "internalType": "uint256" }, - { "name": "leafCount", "type": "uint256", "indexed": false, "internalType": "uint256" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PiecesAdded", - "inputs": [ - { "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "pieceIds", "type": "uint256[]", "indexed": false, "internalType": "uint256[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PiecesRemoved", - "inputs": [ - { "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "pieceIds", "type": "uint256[]", "indexed": false, "internalType": "uint256[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PossessionProven", - "inputs": [ - { "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { - "name": "challenges", - "type": "tuple[]", - "indexed": false, - "internalType": "struct IPDPTypes.PieceIdAndOffset[]", - "components": [ - { "name": "pieceId", "type": "uint256", "internalType": "uint256" }, - { "name": "offset", "type": "uint256", "internalType": "uint256" } - ] - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "DataSetEmpty", - "inputs": [{ "name": "setId", "type": "uint256", "indexed": true, "internalType": "uint256" }], - "anonymous": false - } -] diff --git a/subgraph/abis/ServiceProviderRegistry.json b/subgraph/abis/ServiceProviderRegistry.json deleted file mode 100644 index a2bb58c4..00000000 --- a/subgraph/abis/ServiceProviderRegistry.json +++ /dev/null @@ -1,128 +0,0 @@ -[ - { - "type": "function", - "name": "getProvider", - "inputs": [{ "name": "providerId", "type": "uint256", "internalType": "uint256" }], - "outputs": [ - { - "name": "info", - "type": "tuple", - "internalType": "struct ServiceProviderRegistryStorage.ServiceProviderInfo", - "components": [ - { "name": "serviceProvider", "type": "address", "internalType": "address" }, - { "name": "payee", "type": "address", "internalType": "address" }, - { "name": "name", "type": "string", "internalType": "string" }, - { "name": "description", "type": "string", "internalType": "string" }, - { "name": "isActive", "type": "bool", "internalType": "bool" } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getProviderByAddress", - "inputs": [{ "name": "providerAddress", "type": "address", "internalType": "address" }], - "outputs": [ - { - "name": "info", - "type": "tuple", - "internalType": "struct ServiceProviderRegistryStorage.ServiceProviderInfo", - "components": [ - { "name": "serviceProvider", "type": "address", "internalType": "address" }, - { "name": "payee", "type": "address", "internalType": "address" }, - { "name": "name", "type": "string", "internalType": "string" }, - { "name": "description", "type": "string", "internalType": "string" }, - { "name": "isActive", "type": "bool", "internalType": "bool" } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getProduct", - "inputs": [ - { "name": "providerId", "type": "uint256", "internalType": "uint256" }, - { "name": "productType", "type": "uint8", "internalType": "enum ServiceProviderRegistryStorage.ProductType" } - ], - "outputs": [ - { "name": "productData", "type": "bytes", "internalType": "bytes" }, - { "name": "capabilityKeys", "type": "string[]", "internalType": "string[]" }, - { "name": "isActive", "type": "bool", "internalType": "bool" } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "ProductAdded", - "inputs": [ - { "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { - "name": "productType", - "type": "uint8", - "indexed": true, - "internalType": "enum ServiceProviderRegistryStorage.ProductType" - }, - { "name": "serviceUrl", "type": "string", "indexed": false, "internalType": "string" }, - { "name": "serviceProvider", "type": "address", "indexed": false, "internalType": "address" }, - { "name": "capabilityKeys", "type": "string[]", "indexed": false, "internalType": "string[]" }, - { "name": "capabilityValues", "type": "string[]", "indexed": false, "internalType": "string[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProductRemoved", - "inputs": [ - { "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { - "name": "productType", - "type": "uint8", - "indexed": true, - "internalType": "enum ServiceProviderRegistryStorage.ProductType" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProductUpdated", - "inputs": [ - { "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { - "name": "productType", - "type": "uint8", - "indexed": true, - "internalType": "enum ServiceProviderRegistryStorage.ProductType" - }, - { "name": "serviceUrl", "type": "string", "indexed": false, "internalType": "string" }, - { "name": "serviceProvider", "type": "address", "indexed": false, "internalType": "address" }, - { "name": "capabilityKeys", "type": "string[]", "indexed": false, "internalType": "string[]" }, - { "name": "capabilityValues", "type": "string[]", "indexed": false, "internalType": "string[]" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProviderInfoUpdated", - "inputs": [{ "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }], - "anonymous": false - }, - { - "type": "event", - "name": "ProviderRegistered", - "inputs": [ - { "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }, - { "name": "serviceProvider", "type": "address", "indexed": true, "internalType": "address" }, - { "name": "payee", "type": "address", "indexed": true, "internalType": "address" } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProviderRemoved", - "inputs": [{ "name": "providerId", "type": "uint256", "indexed": true, "internalType": "uint256" }], - "anonymous": false - } -] diff --git a/subgraph/schemas/schema.v1.graphql b/subgraph/schemas/schema.v1.graphql index 5af3e3fb..4dfd0e40 100644 --- a/subgraph/schemas/schema.v1.graphql +++ b/subgraph/schemas/schema.v1.graphql @@ -107,8 +107,8 @@ type Provider @entity(immutable: false) { type ProviderProduct @entity(immutable: false) { id: ID! provider: Provider! - serviceUrl: String productData: Bytes! + decodedProductData: String! productType: BigInt! capabilityKeys: [String!] capabilityValues: [String!] diff --git a/subgraph/src/filecoin-warm-storage-service-legacy.ts b/subgraph/src/filecoin-warm-storage-service-legacy.ts new file mode 100644 index 00000000..1605b7db --- /dev/null +++ b/subgraph/src/filecoin-warm-storage-service-legacy.ts @@ -0,0 +1,41 @@ +/** + * Legacy handler for FilecoinWarmStorageService + * + * Purpose: + * Keeps old event formats indexable after contract upgrades (e.g., PieceAdded before pieceCid). + * + * Upgrade path: + * - Export old ABI → add legacy data source in subgraph.yaml + * - Define handler here for that version + * - Main handler tracks only the latest version + * + * Remove this once all data from old contracts is fully migrated or no longer needed. + */ + +import { PieceAdded as PieceAddedEvent } from "../generated/FilecoinWarmStorageServiceLegacy/FilecoinWarmStorageServiceLegacy"; +import { getPieceCidData } from "./utils/contract-calls"; +import { ContractAddresses } from "./utils/constants"; +import { handlePieceAddedCommon } from "./utils/entity"; + +/** + * Handles the PieceAdded event with definition- PieceAdded(indexed uint256,indexed uint256,string[],string[]) + * Parses the pieceCid from the contract and creates a new piece. + */ +export function handlePieceAdded(event: PieceAddedEvent): void { + const setId = event.params.dataSetId; + const pieceId = event.params.pieceId; + const metadataKeys = event.params.keys; + const metadataValues = event.params.values; + + const pieceBytes = getPieceCidData(ContractAddresses.PDPVerifier, setId, pieceId); + + handlePieceAddedCommon( + setId, + pieceId, + metadataKeys, + metadataValues, + pieceBytes, + event.block.timestamp, + event.block.number, + ); +} diff --git a/subgraph/src/filecoin-warm-storage-service.ts b/subgraph/src/filecoin-warm-storage-service.ts index 4041a590..6b648632 100644 --- a/subgraph/src/filecoin-warm-storage-service.ts +++ b/subgraph/src/filecoin-warm-storage-service.ts @@ -5,8 +5,7 @@ import { ProviderApproved as ProviderApprovedEvent, ProviderUnapproved as ProviderUnapprovedEvent, RailRateUpdated as RailRateUpdatedEvent, - PieceAdded as PieceAddedEventV1, - PieceAdded1 as PieceAddedEventV2, + PieceAdded as PieceAddedEvent, DataSetServiceProviderChanged as DataSetServiceProviderChangedEvent, PDPPaymentTerminated as PDPPaymentTerminatedEvent, CDNPaymentTerminated as CDNPaymentTerminatedEvent, @@ -18,14 +17,13 @@ import { BIGINT_ONE, BIGINT_ZERO, ContractAddresses, - LeafSize, METADATA_KEY_WITH_CDN, NumChallenges, } from "./utils/constants"; import { SumTree } from "./utils/sumTree"; -import { createRails } from "./utils/entity"; +import { createRails, handlePieceAddedCommon } from "./utils/entity"; import { ProviderStatus, RailType } from "./utils/types"; -import { getPieceCidData, getServiceProviderInfo } from "./utils/contract-calls"; +import { getServiceProviderInfo } from "./utils/contract-calls"; import { getDataSetEntityId, getPieceEntityId, @@ -33,7 +31,6 @@ import { getEventLogEntityId, getRateChangeQueueEntityId, } from "./utils/keys"; -import { unpaddedSize, validateCommPv2 } from "./utils/cid"; /** * Pads a Buffer or Uint8Array to 32 bytes with leading zeros. @@ -358,100 +355,11 @@ export function handleRailRateUpdated(event: RailRateUpdatedEvent): void { rail.save(); } -/** - * Common logic for handling PieceAdded events. - * Creates a new piece and updates related entities. - */ -function handlePieceAddedCommon( - setId: BigInt, - pieceId: BigInt, - metadataKeys: string[], - metadataValues: string[], - pieceBytes: Bytes, - blockTimestamp: BigInt, - blockNumber: BigInt, -): void { - const commPData = validateCommPv2(pieceBytes); - const rawSize = commPData.isValid ? unpaddedSize(commPData.padding, commPData.height) : BigInt.zero(); - - const pieceEntityId = getPieceEntityId(setId, pieceId); - const piece = new Piece(pieceEntityId); - piece.pieceId = pieceId; - piece.setId = setId; - piece.rawSize = rawSize; - piece.leafCount = rawSize.div(BigInt.fromI32(LeafSize)); - piece.cid = pieceBytes.length > 0 ? pieceBytes : Bytes.empty(); - piece.metadataKeys = metadataKeys; - piece.metadataValues = metadataValues; - piece.removed = false; - piece.lastProvenEpoch = BIGINT_ZERO; - piece.lastProvenAt = BIGINT_ZERO; - piece.lastFaultedEpoch = BIGINT_ZERO; - piece.lastFaultedAt = BIGINT_ZERO; - piece.totalProofsSubmitted = BIGINT_ZERO; - piece.totalPeriodsFaulted = BIGINT_ZERO; - piece.createdAt = blockTimestamp; - piece.updatedAt = blockTimestamp; - piece.blockNumber = blockNumber; - piece.dataSet = getDataSetEntityId(setId); - - piece.save(); - - const dataSet = DataSet.load(getDataSetEntityId(setId)); - if (!dataSet) { - log.warning("handlePieceAdded: DataSet not found for setId: {}", [setId.toString()]); - return; - } - - dataSet.totalPieces = dataSet.totalPieces.plus(BIGINT_ONE); - dataSet.nextPieceId = dataSet.nextPieceId.plus(BIGINT_ONE); - dataSet.totalDataSize = dataSet.totalDataSize.plus(piece.rawSize); - dataSet.leafCount = dataSet.leafCount.plus(piece.rawSize.div(BigInt.fromI32(LeafSize))); - dataSet.updatedAt = blockTimestamp; - dataSet.blockNumber = blockNumber; - dataSet.save(); - - const provider = Provider.load(dataSet.serviceProvider); - if (!provider) { - log.warning("handlePieceAdded: Provider not found for DataSet: {}", [dataSet.id.toString()]); - return; - } - - provider.totalDataSize = provider.totalDataSize.plus(piece.rawSize); - provider.totalPieces = provider.totalPieces.plus(BIGINT_ONE); - provider.updatedAt = blockTimestamp; - provider.blockNumber = blockNumber; - provider.save(); -} - -/** - * Handles the PieceAdded event with definition- PieceAdded(indexed uint256,indexed uint256,string[],string[]) - * Parses the pieceCid from the contract and creates a new piece. - */ -export function handlePieceAddedV1(event: PieceAddedEventV1): void { - const setId = event.params.dataSetId; - const pieceId = event.params.pieceId; - const metadataKeys = event.params.keys; - const metadataValues = event.params.values; - - const pieceBytes = getPieceCidData(ContractAddresses.PDPVerifier, setId, pieceId); - - handlePieceAddedCommon( - setId, - pieceId, - metadataKeys, - metadataValues, - pieceBytes, - event.block.timestamp, - event.block.number, - ); -} - /** * Handles the PieceAdded event with definition- PieceAdded(indexed uint256,indexed uint256,(bytes),string[],string[]) * Parses the pieceCid from the event and creates a new piece. */ -export function handlePieceAddedV2(event: PieceAddedEventV2): void { +export function handlePieceAdded(event: PieceAddedEvent): void { const setId = event.params.dataSetId; const pieceId = event.params.pieceId; const metadataKeys = event.params.keys; diff --git a/subgraph/src/service-provider-registry.ts b/subgraph/src/service-provider-registry.ts index 8acbaabe..0eba4f48 100644 --- a/subgraph/src/service-provider-registry.ts +++ b/subgraph/src/service-provider-registry.ts @@ -9,7 +9,7 @@ import { } from "../generated/ServiceProviderRegistry/ServiceProviderRegistry"; import { Provider, ProviderProduct } from "../generated/schema"; import { BIGINT_ONE } from "./utils/constants"; -import { getServiceProviderInfo } from "./utils/contract-calls"; +import { decodePDPOfferingData, getProviderProductData, getServiceProviderInfo } from "./utils/contract-calls"; import { createProviderProduct, initiateProvider } from "./utils/entity"; import { getProviderProductEntityId } from "./utils/keys"; @@ -98,6 +98,7 @@ export function handleProductAdded(event: ProductAddedEvent): void { * @param event The ProductUpdated event. */ export function handleProductUpdated(event: ProductUpdatedEvent): void { + const providerId = event.params.providerId; const productType = event.params.productType; const serviceProvider = event.params.serviceProvider; const capabilityKeys = event.params.capabilityKeys; @@ -113,9 +114,13 @@ export function handleProductUpdated(event: ProductUpdatedEvent): void { return; } + const productData = getProviderProductData(event.address, providerId, productType); + const decodedProductData = decodePDPOfferingData(event.address, productData); + providerProduct.capabilityKeys = capabilityKeys; providerProduct.capabilityValues = capabilityValues; - providerProduct.serviceUrl = serviceUrl; + providerProduct.productData = productData; + providerProduct.decodedProductData = decodedProductData.toJSON(); providerProduct.isActive = true; providerProduct.save(); } diff --git a/subgraph/src/utils/contract-calls.ts b/subgraph/src/utils/contract-calls.ts index 3a1786b3..456273a3 100644 --- a/subgraph/src/utils/contract-calls.ts +++ b/subgraph/src/utils/contract-calls.ts @@ -1,6 +1,6 @@ import { Address, BigInt, Bytes, log } from "@graphprotocol/graph-ts"; import { ServiceProviderRegistry } from "../../generated/ServiceProviderRegistry/ServiceProviderRegistry"; -import { ServiceProviderInfo } from "./types"; +import { PDPOffering, ServiceProviderInfo } from "./types"; import { PDPVerifier } from "../../generated/PDPVerifier/PDPVerifier"; export function getServiceProviderInfo(registryAddress: Address, providerId: BigInt): ServiceProviderInfo { @@ -14,11 +14,11 @@ export function getServiceProviderInfo(registryAddress: Address, providerId: Big } return new ServiceProviderInfo( - providerInfoTry.value.serviceProvider, - providerInfoTry.value.payee, - providerInfoTry.value.name, - providerInfoTry.value.description, - providerInfoTry.value.isActive, + providerInfoTry.value.info.serviceProvider, + providerInfoTry.value.info.payee, + providerInfoTry.value.info.name, + providerInfoTry.value.info.description, + providerInfoTry.value.info.isActive, ); } @@ -50,3 +50,26 @@ export function getPieceCidData(verifierAddress: Address, setId: BigInt, pieceId return pieceCidTry.value.data; } + +export function decodePDPOfferingData(registryAddress: Address, data: Bytes): PDPOffering { + const serviceProviderRegistryInstance = ServiceProviderRegistry.bind(registryAddress); + + const pdpOfferingTry = serviceProviderRegistryInstance.try_decodePDPOffering(data); + + if (pdpOfferingTry.reverted) { + log.warning("decodePDPOfferingData: contract call reverted for data: {}", [data.toHexString()]); + return PDPOffering.empty(); + } + + return new PDPOffering( + pdpOfferingTry.value.serviceURL, + pdpOfferingTry.value.minPieceSizeInBytes, + pdpOfferingTry.value.maxPieceSizeInBytes, + pdpOfferingTry.value.ipniPiece, + pdpOfferingTry.value.ipniIpfs, + pdpOfferingTry.value.storagePricePerTibPerMonth, + pdpOfferingTry.value.minProvingPeriodInEpochs, + pdpOfferingTry.value.location, + pdpOfferingTry.value.paymentTokenAddress, + ); +} diff --git a/subgraph/src/utils/entity.ts b/subgraph/src/utils/entity.ts index c528bded..cfcdd342 100644 --- a/subgraph/src/utils/entity.ts +++ b/subgraph/src/utils/entity.ts @@ -1,10 +1,11 @@ -import { Bytes, BigInt, Address } from "@graphprotocol/graph-ts"; -import { Provider, ProviderProduct, Rail } from "../../generated/schema"; -import { BIGINT_ZERO, ContractAddresses } from "./constants"; -import { ProviderStatus } from "./types"; +import { Bytes, BigInt, Address, log } from "@graphprotocol/graph-ts"; +import { Provider, ProviderProduct, Rail, DataSet, Piece } from "../../generated/schema"; import { ProductAdded as ProductAddedEvent } from "../../generated/ServiceProviderRegistry/ServiceProviderRegistry"; -import { getProviderProductEntityId } from "./keys"; -import { getProviderProductData } from "./contract-calls"; +import { BIGINT_ZERO, BIGINT_ONE, ContractAddresses, LeafSize } from "./constants"; +import { ProviderStatus } from "./types"; +import { getProviderProductEntityId, getPieceEntityId, getDataSetEntityId } from "./keys"; +import { decodePDPOfferingData, getProviderProductData } from "./contract-calls"; +import { validateCommPv2, unpaddedSize } from "./cid"; export function createRails( railIds: BigInt[], @@ -45,14 +46,15 @@ export function createProviderProduct(event: ProductAddedEvent): void { const serviceProvider = event.params.serviceProvider; const capabilityKeys = event.params.capabilityKeys; const capabilityValues = event.params.capabilityValues; - const serviceUrl = event.params.serviceUrl; const productId = getProviderProductEntityId(serviceProvider, productType); const providerProduct = new ProviderProduct(productId); + const productData = getProviderProductData(event.address, providerId, productType); + providerProduct.provider = serviceProvider; - providerProduct.serviceUrl = serviceUrl; - providerProduct.productData = getProviderProductData(event.address, providerId, productType); + providerProduct.productData = productData; + providerProduct.decodedProductData = decodePDPOfferingData(event.address, productData).toJSON(); providerProduct.productType = BigInt.fromI32(productType); providerProduct.capabilityKeys = capabilityKeys; providerProduct.capabilityValues = capabilityValues; @@ -90,3 +92,69 @@ export function initiateProvider( return provider; } + +/** + * Common logic for handling PieceAdded events. + * Creates a new piece and updates related entities. + */ +export function handlePieceAddedCommon( + setId: BigInt, + pieceId: BigInt, + metadataKeys: string[], + metadataValues: string[], + pieceBytes: Bytes, + blockTimestamp: BigInt, + blockNumber: BigInt, +): void { + const commPData = validateCommPv2(pieceBytes); + const rawSize = commPData.isValid ? unpaddedSize(commPData.padding, commPData.height) : BigInt.zero(); + + const pieceEntityId = getPieceEntityId(setId, pieceId); + const piece = new Piece(pieceEntityId); + piece.pieceId = pieceId; + piece.setId = setId; + piece.rawSize = rawSize; + piece.leafCount = rawSize.div(BigInt.fromI32(LeafSize)); + piece.cid = pieceBytes.length > 0 ? pieceBytes : Bytes.empty(); + piece.metadataKeys = metadataKeys; + piece.metadataValues = metadataValues; + piece.removed = false; + piece.lastProvenEpoch = BIGINT_ZERO; + piece.lastProvenAt = BIGINT_ZERO; + piece.lastFaultedEpoch = BIGINT_ZERO; + piece.lastFaultedAt = BIGINT_ZERO; + piece.totalProofsSubmitted = BIGINT_ZERO; + piece.totalPeriodsFaulted = BIGINT_ZERO; + piece.createdAt = blockTimestamp; + piece.updatedAt = blockTimestamp; + piece.blockNumber = blockNumber; + piece.dataSet = getDataSetEntityId(setId); + + piece.save(); + + const dataSet = DataSet.load(getDataSetEntityId(setId)); + if (!dataSet) { + log.warning("handlePieceAdded: DataSet not found for setId: {}", [setId.toString()]); + return; + } + + dataSet.totalPieces = dataSet.totalPieces.plus(BIGINT_ONE); + dataSet.nextPieceId = dataSet.nextPieceId.plus(BIGINT_ONE); + dataSet.totalDataSize = dataSet.totalDataSize.plus(piece.rawSize); + dataSet.leafCount = dataSet.leafCount.plus(piece.rawSize.div(BigInt.fromI32(LeafSize))); + dataSet.updatedAt = blockTimestamp; + dataSet.blockNumber = blockNumber; + dataSet.save(); + + const provider = Provider.load(dataSet.serviceProvider); + if (!provider) { + log.warning("handlePieceAdded: Provider not found for DataSet: {}", [dataSet.id.toString()]); + return; + } + + provider.totalDataSize = provider.totalDataSize.plus(piece.rawSize); + provider.totalPieces = provider.totalPieces.plus(BIGINT_ONE); + provider.updatedAt = blockTimestamp; + provider.blockNumber = blockNumber; + provider.save(); +} diff --git a/subgraph/src/utils/types.ts b/subgraph/src/utils/types.ts index 13269347..7c3369a1 100644 --- a/subgraph/src/utils/types.ts +++ b/subgraph/src/utils/types.ts @@ -1,4 +1,4 @@ -import { Address } from "@graphprotocol/graph-ts"; +import { Address, BigInt } from "@graphprotocol/graph-ts"; /** * Information about a service provider @@ -31,3 +31,38 @@ export class ProviderStatus { static readonly UNAPPROVED: string = "UNAPPROVED"; static readonly REMOVED: string = "REMOVED"; } + +/** + * PDP Offering + */ +export class PDPOffering { + constructor( + public serviceURL: string, + public minPieceSizeInBytes: BigInt, + public maxPieceSizeInBytes: BigInt, + public ipniPiece: boolean, + public ipniIpfs: boolean, + public storagePricePerTibPerMonth: BigInt, + public minProvingPeriodInEpochs: BigInt, + public location: string, + public paymentTokenAddress: Address, + ) {} + + static empty(): PDPOffering { + return new PDPOffering( + "", + BigInt.zero(), + BigInt.zero(), + false, + false, + BigInt.zero(), + BigInt.zero(), + "", + Address.zero(), + ); + } + + toJSON(): string { + return `{"serviceURL": "${this.serviceURL}", "minPieceSizeInBytes": "${this.minPieceSizeInBytes}", "maxPieceSizeInBytes": "${this.maxPieceSizeInBytes}", "ipniPiece": ${this.ipniPiece}, "ipniIpfs": ${this.ipniIpfs}, "storagePricePerTibPerMonth": "${this.storagePricePerTibPerMonth}", "minProvingPeriodInEpochs": "${this.minProvingPeriodInEpochs}", "location": "${this.location}", "paymentTokenAddress": "${this.paymentTokenAddress}"}`; + } +} diff --git a/subgraph/templates/subgraph.template.yaml b/subgraph/templates/subgraph.template.yaml index 146c9c66..09ccda2e 100644 --- a/subgraph/templates/subgraph.template.yaml +++ b/subgraph/templates/subgraph.template.yaml @@ -25,7 +25,7 @@ dataSources: - FaultRecord abis: - name: PDPVerifier - file: ./abis/PDPVerifier.json + file: ../service_contracts/abi/PDPVerifier.abi.json eventHandlers: - event: DataSetDeleted(indexed uint256,uint256) handler: handleDataSetDeleted @@ -58,18 +58,16 @@ dataSources: - FaultRecord abis: - name: FilecoinWarmStorageService - file: ./abis/FilecoinWarmStorageService.json + file: ../service_contracts/abi/FilecoinWarmStorageService.abi.json - name: PDPVerifier - file: ./abis/PDPVerifier.json + file: ../service_contracts/abi/PDPVerifier.abi.json - name: ServiceProviderRegistry - file: ./abis/ServiceProviderRegistry.json + file: ../service_contracts/abi/ServiceProviderRegistry.abi.json eventHandlers: - event: "DataSetCreated(indexed uint256,indexed uint256,uint256,uint256,uint256,address,address,address,string[],string[])" handler: handleDataSetCreated - - event: "PieceAdded(indexed uint256,indexed uint256,string[],string[])" - handler: handlePieceAddedV1 - event: "PieceAdded(indexed uint256,indexed uint256,(bytes),string[],string[])" - handler: handlePieceAddedV2 + handler: handlePieceAdded - event: "DataSetServiceProviderChanged(indexed uint256,indexed address,indexed address)" handler: handleDataSetServiceProviderChanged - event: "RailRateUpdated(indexed uint256,uint256,uint256)" @@ -87,6 +85,33 @@ dataSources: - event: "PaymentArbitrated(uint256,uint256,uint256,uint256,uint256)" handler: handlePaymentArbitrated file: ./src/filecoin-warm-storage-service.ts + # LEGACY DATA SOURCE: Indexes events from older contract versions so historical data isn’t lost + # Example: PieceAdded event was upgraded - old had (dataSetId, pieceId, keys[], values[]), new has pieceCid param + # Upgrade path: Export old ABI to ./abi/FilecoinWarmStorageServiceLegacy.abi.json → add here → define handler + - kind: ethereum + name: FilecoinWarmStorageServiceLegacy + network: {{name}} + source: + address: "{{FilecoinWarmStorageService.address}}" + abi: FilecoinWarmStorageServiceLegacy + startBlock: {{FilecoinWarmStorageService.startBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.9 + language: wasm/assemblyscript + entities: + - DataSet + - Piece + - Provider + abis: + - name: FilecoinWarmStorageServiceLegacy + file: ./abi/FilecoinWarmStorageServiceLegacy.abi.json + - name: PDPVerifier + file: ../service_contracts/abi/PDPVerifier.abi.json + eventHandlers: + - event: "PieceAdded(indexed uint256,indexed uint256,string[],string[])" + handler: handlePieceAdded + file: ./src/filecoin-warm-storage-service-legacy.ts - kind: ethereum name: ServiceProviderRegistry network: {{name}} @@ -104,7 +129,7 @@ dataSources: - ProviderProduct abis: - name: ServiceProviderRegistry - file: ./abis/ServiceProviderRegistry.json + file: ../service_contracts/abi/ServiceProviderRegistry.abi.json eventHandlers: - event: "ProviderRegistered(indexed uint256,indexed address,indexed address)" handler: handleProviderRegistered