bindings.go 18.6 KB
Newer Older
1
package go_sectorbuilder
2
3

import (
4
	"bytes"
5
6
	"os"
	"runtime"
7
	"sort"
8
9
10
	"time"
	"unsafe"

11
	"github.com/filecoin-project/go-sectorbuilder/sealed_sector_health"
12
	"github.com/filecoin-project/go-sectorbuilder/sealing_state"
13

14
15
16
17
	logging "github.com/ipfs/go-log"
	"github.com/pkg/errors"
)

18
19
20
// #cgo LDFLAGS: ${SRCDIR}/libsector_builder_ffi.a
// #cgo pkg-config: ${SRCDIR}/sector_builder_ffi.pc
// #include "./sector_builder_ffi.h"
21
22
23
24
25
26
27
28
29
30
31
import "C"

var log = logging.Logger("libsectorbuilder") // nolint: deadcode

func elapsed(what string) func() {
	start := time.Now()
	return func() {
		log.Debugf("%s took %v\n", what, time.Since(start))
	}
}

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// SortedSectorInfo is a slice of SectorInfo sorted (lexicographically,
// ascending) by replica commitment (CommR).
type SortedSectorInfo struct {
	f []SectorInfo
}

// NewSortedSectorInfo returns a SortedSectorInfo
func NewSortedSectorInfo(sectorInfo ...SectorInfo) SortedSectorInfo {
	fn := func(i, j int) bool {
		return bytes.Compare(sectorInfo[i].CommR[:], sectorInfo[j].CommR[:]) == -1
	}

	sort.Slice(sectorInfo[:], fn)

	return SortedSectorInfo{
		f: sectorInfo,
	}
}

// Values returns the sorted SectorInfo as a slice
func (s *SortedSectorInfo) Values() []SectorInfo {
	return s.f
}

type SectorInfo struct {
	SectorID uint64
58
	CommR    [CommitmentBytesLen]byte
59
60
}

61
62
63
// CommitmentBytesLen is the number of bytes in a CommR, CommD, CommP, and CommRStar.
const CommitmentBytesLen = 32

64
65
66
67
68
69
70
// StagedSectorMetadata is a sector into which we write user piece-data before
// sealing. Note: SectorID is unique across all staged and sealed sectors for a
// storage miner actor.
type StagedSectorMetadata struct {
	SectorID uint64
}

Sidney Keese's avatar
Sidney Keese committed
71
72
73
74
75
76
77
78
// SealedSectorMetadata represents a sector in the builder that has been sealed.
type SealedSectorMetadata struct {
	SectorID  uint64
	CommD     [CommitmentBytesLen]byte
	CommR     [CommitmentBytesLen]byte
	CommRStar [CommitmentBytesLen]byte
	Proof     []byte
	Pieces    []PieceMetadata
79
	Health    sealed_sector_health.Health
Sidney Keese's avatar
Sidney Keese committed
80
81
}

82
83
84
// SectorSealingStatus communicates how far along in the sealing process a
// sector has progressed.
type SectorSealingStatus struct {
85
86
87
88
89
90
91
92
	SectorID     uint64
	State        sealing_state.State
	SealErrorMsg string                   // will be nil unless State == Failed
	CommD        [CommitmentBytesLen]byte // will be empty unless State == Sealed
	CommR        [CommitmentBytesLen]byte // will be empty unless State == Sealed
	CommRStar    [CommitmentBytesLen]byte // will be empty unless State == Sealed
	Proof        []byte                   // will be empty unless State == Sealed
	Pieces       []PieceMetadata          // will be empty unless State == Sealed
93
94
95
96
97
98
99
}

// PieceMetadata represents a piece stored by the sector builder.
type PieceMetadata struct {
	Key            string
	Size           uint64
	InclusionProof []byte
100
	CommP          [CommitmentBytesLen]byte
101
102
103
104
105
106
}

// VerifySeal returns true if the sealing operation from which its inputs were
// derived was valid, and false if not.
func VerifySeal(
	sectorSize uint64,
107
108
109
	commR [CommitmentBytesLen]byte,
	commD [CommitmentBytesLen]byte,
	commRStar [CommitmentBytesLen]byte,
110
	proverID [31]byte,
laser's avatar
laser committed
111
	sectorID uint64,
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
	proof []byte,
) (bool, error) {
	defer elapsed("VerifySeal")()

	commDCBytes := C.CBytes(commD[:])
	defer C.free(commDCBytes)

	commRCBytes := C.CBytes(commR[:])
	defer C.free(commRCBytes)

	commRStarCBytes := C.CBytes(commRStar[:])
	defer C.free(commRStarCBytes)

	proofCBytes := C.CBytes(proof[:])
	defer C.free(proofCBytes)

	proverIDCBytes := C.CBytes(proverID[:])
	defer C.free(proverIDCBytes)

	// a mutable pointer to a VerifySealResponse C-struct
132
	resPtr := C.sector_builder_ffi_verify_seal(
133
		C.uint64_t(sectorSize),
134
135
136
		(*[CommitmentBytesLen]C.uint8_t)(commRCBytes),
		(*[CommitmentBytesLen]C.uint8_t)(commDCBytes),
		(*[CommitmentBytesLen]C.uint8_t)(commRStarCBytes),
137
		(*[31]C.uint8_t)(proverIDCBytes),
laser's avatar
laser committed
138
		C.uint64_t(sectorID),
139
140
		(*C.uint8_t)(proofCBytes),
		C.size_t(len(proof)),
141
	)
142
143
144
145
146
147
148
149
150
151
152
153
154
	defer C.sector_builder_ffi_destroy_verify_seal_response(resPtr)

	if resPtr.status_code != 0 {
		return false, errors.New(C.GoString(resPtr.error_msg))
	}

	return bool(resPtr.is_valid), nil
}

// VerifyPoSt returns true if the PoSt-generation operation from which its
// inputs were derived was valid, and false if not.
func VerifyPoSt(
	sectorSize uint64,
155
	sectorInfo SortedSectorInfo,
laser's avatar
laser committed
156
157
	challengeSeed [32]byte,
	proof []byte,
158
159
160
161
	faults []uint64,
) (bool, error) {
	defer elapsed("VerifyPoSt")()

162
163
164
165
166
167
168
169
	// CommRs and sector ids must be provided to C.verify_post in the same order
	// that they were provided to the C.generate_post
	sortedCommRs := make([][CommitmentBytesLen]byte, len(sectorInfo.Values()))
	sortedSectorIds := make([]uint64, len(sectorInfo.Values()))
	for idx, v := range sectorInfo.Values() {
		sortedCommRs[idx] = v.CommR
		sortedSectorIds[idx] = v.SectorID
	}
170
171

	// flattening the byte slice makes it easier to copy into the C heap
172
173
	flattened := make([]byte, CommitmentBytesLen*len(sortedCommRs))
	for idx, commR := range sortedCommRs {
174
		copy(flattened[(CommitmentBytesLen*idx):(CommitmentBytesLen*(1+idx))], commR[:])
175
176
177
178
179
180
181
182
183
	}

	// copy bytes from Go to C heap
	flattenedCommRsCBytes := C.CBytes(flattened)
	defer C.free(flattenedCommRsCBytes)

	challengeSeedCBytes := C.CBytes(challengeSeed[:])
	defer C.free(challengeSeedCBytes)

laser's avatar
laser committed
184
185
	proofCBytes := C.CBytes(proof)
	defer C.free(proofCBytes)
186
187

	// allocate fixed-length array of uint64s in C heap
laser's avatar
laser committed
188
189
190
	sectorIdsPtr, sectorIdsSize := cUint64s(sortedSectorIds)
	defer C.free(unsafe.Pointer(sectorIdsPtr))

191
192
193
194
	faultsPtr, faultsSize := cUint64s(faults)
	defer C.free(unsafe.Pointer(faultsPtr))

	// a mutable pointer to a VerifyPoStResponse C-struct
195
	resPtr := C.sector_builder_ffi_verify_post(
196
		C.uint64_t(sectorSize),
197
		(*[CommitmentBytesLen]C.uint8_t)(challengeSeedCBytes),
laser's avatar
laser committed
198
199
		sectorIdsPtr,
		sectorIdsSize,
200
201
		faultsPtr,
		faultsSize,
laser's avatar
laser committed
202
203
204
205
		(*C.uint8_t)(flattenedCommRsCBytes),
		C.size_t(len(flattened)),
		(*C.uint8_t)(proofCBytes),
		C.size_t(len(proof)),
206
	)
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
	defer C.sector_builder_ffi_destroy_verify_post_response(resPtr)

	if resPtr.status_code != 0 {
		return false, errors.New(C.GoString(resPtr.error_msg))
	}

	return bool(resPtr.is_valid), nil
}

// GetMaxUserBytesPerStagedSector returns the number of user bytes that will fit
// into a staged sector. Due to bit-padding, the number of user bytes that will
// fit into the staged sector will be less than number of bytes in sectorSize.
func GetMaxUserBytesPerStagedSector(sectorSize uint64) uint64 {
	defer elapsed("GetMaxUserBytesPerStagedSector")()

	return uint64(C.sector_builder_ffi_get_max_user_bytes_per_staged_sector(C.uint64_t(sectorSize)))
}

// InitSectorBuilder allocates and returns a pointer to a sector builder.
func InitSectorBuilder(
	sectorSize uint64,
	poRepProofPartitions uint8,
	poStProofPartitions uint8,
	lastUsedSectorID uint64,
	metadataDir string,
	proverID [31]byte,
	sealedSectorDir string,
	stagedSectorDir string,
	maxNumOpenStagedSectors uint8,
) (unsafe.Pointer, error) {
	defer elapsed("InitSectorBuilder")()

	cMetadataDir := C.CString(metadataDir)
	defer C.free(unsafe.Pointer(cMetadataDir))

	proverIDCBytes := C.CBytes(proverID[:])
	defer C.free(proverIDCBytes)

	cStagedSectorDir := C.CString(stagedSectorDir)
	defer C.free(unsafe.Pointer(cStagedSectorDir))

	cSealedSectorDir := C.CString(sealedSectorDir)
	defer C.free(unsafe.Pointer(cSealedSectorDir))

laser's avatar
laser committed
251
	class, err := cSectorClass(sectorSize, poRepProofPartitions)
252
253
254
255
	if err != nil {
		return nil, errors.Wrap(err, "failed to get sector class")
	}

256
	resPtr := C.sector_builder_ffi_init_sector_builder(
257
258
259
260
261
262
263
		class,
		C.uint64_t(lastUsedSectorID),
		cMetadataDir,
		(*[31]C.uint8_t)(proverIDCBytes),
		cSealedSectorDir,
		cStagedSectorDir,
		C.uint8_t(maxNumOpenStagedSectors),
264
	)
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
	defer C.sector_builder_ffi_destroy_init_sector_builder_response(resPtr)

	if resPtr.status_code != 0 {
		return nil, errors.New(C.GoString(resPtr.error_msg))
	}

	return unsafe.Pointer(resPtr.sector_builder), nil
}

// DestroySectorBuilder deallocates the sector builder associated with the
// provided pointer. This function will panic if the provided pointer is null
// or if the sector builder has been previously deallocated.
func DestroySectorBuilder(sectorBuilderPtr unsafe.Pointer) {
	defer elapsed("DestroySectorBuilder")()

	C.sector_builder_ffi_destroy_sector_builder((*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr))
}

283
// AddPiece writes the given piece into an unsealed sector and returns the id of that sector.
284
285
286
func AddPiece(
	sectorBuilderPtr unsafe.Pointer,
	pieceKey string,
287
	pieceBytes uint64,
288
	piecePath string,
289
) (uint64, error) {
290
291
	defer elapsed("AddPiece")()

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
	pieceFile, err := os.Open(piecePath)
	if err != nil {
		return 0, err
	}

	return AddPieceFromFile(sectorBuilderPtr, pieceKey, pieceBytes, pieceFile)
}

// AddPieceFromFile writes the given piece into an unsealed sector and returns the id of that sector.
func AddPieceFromFile(
	sectorBuilderPtr unsafe.Pointer,
	pieceKey string,
	pieceBytes uint64,
	pieceFile *os.File,
) (sectorID uint64, retErr error) {
	defer elapsed("AddPieceFromFile")()

309
310
311
	cPieceKey := C.CString(pieceKey)
	defer C.free(unsafe.Pointer(cPieceKey))

312
	pieceFd := pieceFile.Fd()
313

314
315
316
317
318
319
320
321
322
323
	// TODO: The UTC time, in seconds, at which the sector builder can safely
	// delete the piece. This allows for co-location of pieces with similar time
	// constraints, and allows the sector builder to remove sectors containing
	// pieces whose deals have expired.
	//
	// This value is currently ignored by the sector builder.
	//
	// https://github.com/filecoin-project/rust-fil-sector-builder/issues/32
	pieceExpiryUtcSeconds := 0

324
	resPtr := C.sector_builder_ffi_add_piece(
325
326
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		cPieceKey,
327
328
		C.int(pieceFd),
		C.uint64_t(pieceBytes),
329
		C.uint64_t(pieceExpiryUtcSeconds),
330
	)
331
332
	defer C.sector_builder_ffi_destroy_add_piece_response(resPtr)

333
334
335
	// Make sure our filedescriptor stays alive, stayin alive
	runtime.KeepAlive(pieceFile)

336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
	if resPtr.status_code != 0 {
		return 0, errors.New(C.GoString(resPtr.error_msg))
	}

	return uint64(resPtr.sector_id), nil
}

// ReadPieceFromSealedSector produces a byte buffer containing the piece
// associated with the provided key. If the key is not associated with any piece
// yet sealed into a sector, an error will be returned.
func ReadPieceFromSealedSector(sectorBuilderPtr unsafe.Pointer, pieceKey string) ([]byte, error) {
	defer elapsed("ReadPieceFromSealedSector")()

	cPieceKey := C.CString(pieceKey)
	defer C.free(unsafe.Pointer(cPieceKey))

352
353
354
355
	resPtr := C.sector_builder_ffi_read_piece_from_sealed_sector(
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		cPieceKey,
	)
356
357
358
359
360
361
362
363
364
365
366
367
368
	defer C.sector_builder_ffi_destroy_read_piece_from_sealed_sector_response(resPtr)

	if resPtr.status_code != 0 {
		return nil, errors.New(C.GoString(resPtr.error_msg))
	}

	return goBytes(resPtr.data_ptr, resPtr.data_len), nil
}

// SealAllStagedSectors schedules sealing of all staged sectors.
func SealAllStagedSectors(sectorBuilderPtr unsafe.Pointer) error {
	defer elapsed("SealAllStagedSectors")()

369
	resPtr := C.sector_builder_ffi_seal_all_staged_sectors((*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr))
370
371
372
373
374
375
376
377
378
379
380
381
382
	defer C.sector_builder_ffi_destroy_seal_all_staged_sectors_response(resPtr)

	if resPtr.status_code != 0 {
		return errors.New(C.GoString(resPtr.error_msg))
	}

	return nil
}

// GetAllStagedSectors returns a slice of all staged sector metadata for the sector builder.
func GetAllStagedSectors(sectorBuilderPtr unsafe.Pointer) ([]StagedSectorMetadata, error) {
	defer elapsed("GetAllStagedSectors")()

383
	resPtr := C.sector_builder_ffi_get_staged_sectors((*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr))
384
385
386
387
388
389
	defer C.sector_builder_ffi_destroy_get_staged_sectors_response(resPtr)

	if resPtr.status_code != 0 {
		return nil, errors.New(C.GoString(resPtr.error_msg))
	}

390
	meta, err := goStagedSectorMetadata(resPtr.sectors_ptr, resPtr.sectors_len)
391
392
393
394
395
396
397
	if err != nil {
		return nil, err
	}

	return meta, nil
}

398
399
400
// GetAllSealedSectors returns a slice of all sealed sector metadata, excluding
// sector health.
func GetAllSealedSectors(sectorBuilderPtr unsafe.Pointer) ([]SealedSectorMetadata, error) {
Sidney Keese's avatar
Sidney Keese committed
401
402
	defer elapsed("GetAllSealedSectors")()

403
404
	return getAllSealedSectors(sectorBuilderPtr, false)
}
Sidney Keese's avatar
Sidney Keese committed
405

406
407
408
409
410
// GetAllSealedSectorsWithHealth returns a slice of all sealed sector metadata
// for the sector builder, including sector health info (which can be expensive
// to compute).
func GetAllSealedSectorsWithHealth(sectorBuilderPtr unsafe.Pointer) ([]SealedSectorMetadata, error) {
	defer elapsed("GetAllSealedSectorsWithHealth")()
Sidney Keese's avatar
Sidney Keese committed
411

412
	return getAllSealedSectors(sectorBuilderPtr, true)
Sidney Keese's avatar
Sidney Keese committed
413
414
}

415
416
417
// GetSectorSealingStatusByID produces sector sealing status (staged, sealing in
// progress, sealed, failed) for the provided sector id. If no sector
// corresponding to the provided id exists, this function returns an error.
418
419
420
func GetSectorSealingStatusByID(sectorBuilderPtr unsafe.Pointer, sectorID uint64) (SectorSealingStatus, error) {
	defer elapsed("GetSectorSealingStatusByID")()

421
422
423
424
	resPtr := C.sector_builder_ffi_get_seal_status(
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		C.uint64_t(sectorID),
	)
425
426
427
428
429
430
431
	defer C.sector_builder_ffi_destroy_get_seal_status_response(resPtr)

	if resPtr.status_code != 0 {
		return SectorSealingStatus{}, errors.New(C.GoString(resPtr.error_msg))
	}

	if resPtr.seal_status_code == C.Failed {
432
		return SectorSealingStatus{SectorID: sectorID, State: sealing_state.Failed, SealErrorMsg: C.GoString(resPtr.seal_error_msg)}, nil
433
	} else if resPtr.seal_status_code == C.Pending {
434
		return SectorSealingStatus{SectorID: sectorID, State: sealing_state.Pending}, nil
435
	} else if resPtr.seal_status_code == C.Sealing {
436
		return SectorSealingStatus{SectorID: sectorID, State: sealing_state.Sealing}, nil
437
	} else if resPtr.seal_status_code == C.Sealed {
438
439
		commRSlice := goBytes(&resPtr.comm_r[0], CommitmentBytesLen)
		var commR [CommitmentBytesLen]byte
440
441
		copy(commR[:], commRSlice)

442
443
		commDSlice := goBytes(&resPtr.comm_d[0], CommitmentBytesLen)
		var commD [CommitmentBytesLen]byte
444
445
		copy(commD[:], commDSlice)

446
447
		commRStarSlice := goBytes(&resPtr.comm_r_star[0], CommitmentBytesLen)
		var commRStar [CommitmentBytesLen]byte
448
449
450
451
452
453
454
455
456
457
		copy(commRStar[:], commRStarSlice)

		proof := goBytes(resPtr.proof_ptr, resPtr.proof_len)

		ps, err := goPieceMetadata(resPtr.pieces_ptr, resPtr.pieces_len)
		if err != nil {
			return SectorSealingStatus{}, errors.Wrap(err, "failed to marshal from string to cid")
		}

		return SectorSealingStatus{
458
459
460
461
462
463
464
			SectorID:  sectorID,
			State:     sealing_state.Sealed,
			CommD:     commD,
			CommR:     commR,
			CommRStar: commRStar,
			Proof:     proof,
			Pieces:    ps,
465
466
467
468
469
470
471
472
473
474
		}, nil
	} else {
		// unknown
		return SectorSealingStatus{}, errors.New("unexpected seal status")
	}
}

// GeneratePoSt produces a proof-of-spacetime for the provided replica commitments.
func GeneratePoSt(
	sectorBuilderPtr unsafe.Pointer,
475
	sectorInfo SortedSectorInfo,
476
	challengeSeed [CommitmentBytesLen]byte,
laser's avatar
laser committed
477
478
	faults []uint64,
) ([]byte, error) {
479
480
	defer elapsed("GeneratePoSt")()

481
482
483
484
485
486
487
	// CommRs and sector ids must be provided to C.verify_post in the same order
	// that they were provided to the C.generate_post
	sortedCommRs := make([][CommitmentBytesLen]byte, len(sectorInfo.Values()))
	for idx, v := range sectorInfo.Values() {
		sortedCommRs[idx] = v.CommR
	}

488
	// flattening the byte slice makes it easier to copy into the C heap
489
490
	flattened := make([]byte, CommitmentBytesLen*len(sortedCommRs))
	for idx, commR := range sortedCommRs {
491
		copy(flattened[(CommitmentBytesLen*idx):(CommitmentBytesLen*(1+idx))], commR[:])
492
493
494
495
496
497
498
499
	}

	// copy the Go byte slice into C memory
	cflattened := C.CBytes(flattened)
	defer C.free(cflattened)

	challengeSeedPtr := unsafe.Pointer(&(challengeSeed)[0])

laser's avatar
laser committed
500
501
502
	faultsPtr, faultsSize := cUint64s(faults)
	defer C.free(unsafe.Pointer(faultsPtr))

503
	// a mutable pointer to a GeneratePoStResponse C-struct
504
505
506
507
508
	resPtr := C.sector_builder_ffi_generate_post(
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		(*C.uint8_t)(cflattened),
		C.size_t(len(flattened)),
		(*[CommitmentBytesLen]C.uint8_t)(challengeSeedPtr),
laser's avatar
laser committed
509
510
		faultsPtr,
		faultsSize,
511
	)
512
513
514
	defer C.sector_builder_ffi_destroy_generate_post_response(resPtr)

	if resPtr.status_code != 0 {
laser's avatar
laser committed
515
		return nil, errors.New(C.GoString(resPtr.error_msg))
516
517
	}

laser's avatar
laser committed
518
	return goBytes(resPtr.proof_ptr, resPtr.proof_len), nil
519
}
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550

// VerifyPieceInclusionProof returns true if the piece inclusion proof is valid
// with the given arguments.
func VerifyPieceInclusionProof(sectorSize uint64, pieceSize uint64, commP [CommitmentBytesLen]byte, commD [CommitmentBytesLen]byte, proof []byte) (bool, error) {
	commDCBytes := C.CBytes(commD[:])
	defer C.free(commDCBytes)

	commPCBytes := C.CBytes(commP[:])
	defer C.free(commPCBytes)

	pieceInclusionProofCBytes := C.CBytes(proof)
	defer C.free(pieceInclusionProofCBytes)

	resPtr := C.sector_builder_ffi_verify_piece_inclusion_proof(
		(*[CommitmentBytesLen]C.uint8_t)(commDCBytes),
		(*[CommitmentBytesLen]C.uint8_t)(commPCBytes),
		(*C.uint8_t)(pieceInclusionProofCBytes),
		C.size_t(len(proof)),
		C.uint64_t(pieceSize),
		C.uint64_t(sectorSize),
	)
	defer C.sector_builder_ffi_destroy_verify_piece_inclusion_proof_response(resPtr)

	if resPtr.status_code != 0 {
		return false, errors.New(C.GoString(resPtr.error_msg))
	}

	return bool(resPtr.is_valid), nil
}

// GeneratePieceCommitment produces a piece commitment for the provided data
551
552
553
554
555
556
// stored at a given path.
func GeneratePieceCommitment(piecePath string, pieceSize uint64) ([CommitmentBytesLen]byte, error) {
	pieceFile, err := os.Open(piecePath)
	if err != nil {
		return [CommitmentBytesLen]byte{}, err
	}
557

558
559
560
561
562
563
564
565
566
	return GeneratePieceCommitmentFromFile(pieceFile, pieceSize)
}

// GeneratePieceCommitmentFromFile produces a piece commitment for the provided data
// stored in a given file.
func GeneratePieceCommitmentFromFile(pieceFile *os.File, pieceSize uint64) (commP [CommitmentBytesLen]byte, err error) {
	pieceFd := pieceFile.Fd()

	resPtr := C.sector_builder_ffi_generate_piece_commitment(C.int(pieceFd), C.uint64_t(pieceSize))
567
568
	defer C.sector_builder_ffi_destroy_generate_piece_commitment_response(resPtr)

569
570
571
	// Make sure our filedescriptor stays alive, stayin alive
	runtime.KeepAlive(pieceFile)

572
573
574
575
576
577
578
579
580
581
	if resPtr.status_code != 0 {
		return [CommitmentBytesLen]byte{}, errors.New(C.GoString(resPtr.error_msg))
	}

	commPSlice := goBytes(&resPtr.comm_p[0], CommitmentBytesLen)
	var commitment [CommitmentBytesLen]byte
	copy(commitment[:], commPSlice)

	return commitment, nil
}
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

func getAllSealedSectors(sectorBuilderPtr unsafe.Pointer, performHealthchecks bool) ([]SealedSectorMetadata, error) {
	resPtr := C.sector_builder_ffi_get_sealed_sectors((*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr), C.bool(performHealthchecks))
	defer C.sector_builder_ffi_destroy_get_sealed_sectors_response(resPtr)

	if resPtr.status_code != 0 {
		return nil, errors.New(C.GoString(resPtr.error_msg))
	}

	meta, err := goSealedSectorMetadata(resPtr.sectors_ptr, resPtr.sectors_len)
	if err != nil {
		return nil, err
	}

	return meta, nil
}