1- import { BigInt , log } from "@graphprotocol/graph-ts" ;
1+ import { BigInt , Bytes , log } from "@graphprotocol/graph-ts" ;
22import {
33 DataSetCreated as DataSetCreatedEvent ,
44 DataSetDeleted as DataSetDeletedEvent ,
55 DataSetEmpty as DataSetEmptyEvent ,
66 NextProvingPeriod as NextProvingPeriodEvent ,
77 PiecesAdded as PiecesAddedEvent ,
8+ PiecesAddedV2 as PiecesAddedV2Event ,
89 PiecesRemoved as PiecesRemovedEvent ,
910 PossessionProven as PossessionProvenEvent ,
1011 StorageProviderChanged as StorageProviderChangedEvent ,
@@ -15,6 +16,7 @@ import {
1516 getRootEntityId ,
1617 getRootSampleKey ,
1718 maxProvingPeriodFor ,
19+ reconstructCidFromPackedCid ,
1820 unpaddedSize ,
1921 validateCommPv2 ,
2022} from "./helpers" ;
@@ -163,12 +165,50 @@ export function handleNextProvingPeriod(event: NextProvingPeriodEvent): void {
163165 }
164166}
165167
168+ // Shared by handlePiecesAdded and handlePiecesAddedV2: creates the Root entity for one added
169+ // piece. Returns false (and logs) if the Root already exists, so the caller can skip counting it
170+ // toward the EMPTY -> READY transition.
171+ function createRootFromPieceCid (
172+ setId : BigInt ,
173+ rootId : BigInt ,
174+ pieceCidBytes : Bytes ,
175+ proofSetEntityId : Bytes ,
176+ blockTimestamp : BigInt ,
177+ ) : boolean {
178+ const commPData = validateCommPv2 ( pieceCidBytes ) ;
179+ const rawSize = commPData . isValid ? unpaddedSize ( commPData . padding , commPData . height ) : BigInt . zero ( ) ;
180+
181+ const rootEntityId = getRootEntityId ( setId , rootId ) ;
182+ if ( Root . load ( rootEntityId ) != null ) {
183+ log . warning ( "createRootFromPieceCid: Root {} for Set {} already exists; skipping" , [
184+ rootId . toString ( ) ,
185+ setId . toString ( ) ,
186+ ] ) ;
187+ return false ;
188+ }
189+
190+ const root = new Root ( rootEntityId ) ;
191+ root . setId = setId ;
192+ root . rootId = rootId ;
193+ root . rawSize = rawSize ;
194+ root . cid = pieceCidBytes ;
195+ root . removed = false ;
196+ root . createdAt = blockTimestamp ;
197+ root . proofSet = proofSetEntityId ;
198+ root . sampleKey = getRootSampleKey ( rootEntityId ) ;
199+ // ipfsRootCID: patched in FWSS handler if applicable.
200+ root . save ( ) ;
201+
202+ return true ;
203+ }
204+
166205export function handlePiecesAdded ( event : PiecesAddedEvent ) : void {
167206 const setId = event . params . setId ;
168207 const rootIdsFromEvent = event . params . pieceIds ;
169208 const pieceCidsFromEvent = event . params . pieceCids ;
170209
171- const proofSet = DataSet . load ( getProofSetEntityId ( setId ) ) ;
210+ const proofSetEntityId = getProofSetEntityId ( setId ) ;
211+ const proofSet = DataSet . load ( proofSetEntityId ) ;
172212 if ( proofSet == null ) {
173213 log . warning ( "handlePiecesAdded: DataSet {} not found" , [ setId . toString ( ) ] ) ;
174214 return ;
@@ -177,35 +217,48 @@ export function handlePiecesAdded(event: PiecesAddedEvent): void {
177217 let addedAny = false ;
178218
179219 for ( let i = 0 ; i < rootIdsFromEvent . length ; i ++ ) {
180- const rootId = rootIdsFromEvent [ i ] ;
181- const pieceCid = pieceCidsFromEvent [ i ] ;
182-
183- const pieceBytes = pieceCid . data ;
184- const commPData = validateCommPv2 ( pieceBytes ) ;
185- const rawSize = commPData . isValid ? unpaddedSize ( commPData . padding , commPData . height ) : BigInt . zero ( ) ;
186-
187- const rootEntityId = getRootEntityId ( setId , rootId ) ;
188- if ( Root . load ( rootEntityId ) != null ) {
189- log . warning ( "handlePiecesAdded: Root {} for Set {} already exists; skipping" , [
190- rootId . toString ( ) ,
191- setId . toString ( ) ,
192- ] ) ;
193- continue ;
194- }
220+ const created = createRootFromPieceCid (
221+ setId ,
222+ rootIdsFromEvent [ i ] ,
223+ pieceCidsFromEvent [ i ] . data ,
224+ proofSetEntityId ,
225+ event . block . timestamp ,
226+ ) ;
227+ if ( created ) addedAny = true ;
228+ }
195229
196- const root = new Root ( rootEntityId ) ;
197- root . setId = setId ;
198- root . rootId = rootId ;
199- root . rawSize = rawSize ;
200- root . cid = pieceBytes ;
201- root . removed = false ;
202- root . createdAt = event . block . timestamp ;
203- root . proofSet = getProofSetEntityId ( setId ) ;
204- root . sampleKey = getRootSampleKey ( rootEntityId ) ;
205- // ipfsRootCID: patched in FWSS handler if applicable.
206- root . save ( ) ;
230+ // First non-empty add transitions the DataSet to READY. NextProvingPeriod
231+ // will then promote it to PROVING.
232+ if ( addedAny && proofSet . status == DataSetStatus . EMPTY ) {
233+ proofSet . status = DataSetStatus . READY ;
234+ proofSet . save ( ) ;
235+ }
236+ }
237+
238+ // Handles the compact PiecesAddedV2 event (PDPVerifier PR #300), which replaces the legacy
239+ // PiecesAdded for all new piece additions (PiecesAdded is kept only for historical logs). Piece
240+ // IDs are contiguous from firstPieceId, and each CID is packed as (header, root) instead of raw
241+ // bytes; a single addPieces call can emit several of these events once pieces are batched.
242+ export function handlePiecesAddedV2 ( event : PiecesAddedV2Event ) : void {
243+ const setId = event . params . setId ;
244+ const firstPieceId = event . params . firstPieceId ;
245+ const pieceCidsFromEvent = event . params . pieceCids ;
246+
247+ const proofSetEntityId = getProofSetEntityId ( setId ) ;
248+ const proofSet = DataSet . load ( proofSetEntityId ) ;
249+ if ( proofSet == null ) {
250+ log . warning ( "handlePiecesAddedV2: DataSet {} not found" , [ setId . toString ( ) ] ) ;
251+ return ;
252+ }
253+
254+ let addedAny = false ;
255+
256+ for ( let i = 0 ; i < pieceCidsFromEvent . length ; i ++ ) {
257+ const rootId = firstPieceId . plus ( BigInt . fromI32 ( i ) ) ;
258+ const pieceCidBytes = reconstructCidFromPackedCid ( pieceCidsFromEvent [ i ] . header , pieceCidsFromEvent [ i ] . root ) ;
207259
208- addedAny = true ;
260+ const created = createRootFromPieceCid ( setId , rootId , pieceCidBytes , proofSetEntityId , event . block . timestamp ) ;
261+ if ( created ) addedAny = true ;
209262 }
210263
211264 // First non-empty add transitions the DataSet to READY. NextProvingPeriod
0 commit comments