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

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

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

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

19
20
21
// #cgo LDFLAGS: ${SRCDIR}/libsector_builder_ffi.a
// #cgo pkg-config: ${SRCDIR}/sector_builder_ffi.pc
// #include "./sector_builder_ffi.h"
22
23
24
25
26
27
28
29
30
31
32
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))
	}
}

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 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
}

57
58
59
60
61
62
63
64
65
66
67
68
69
70
// MarshalJSON JSON-encodes and serializes the SortedSectorInfo.
func (s SortedSectorInfo) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.f)
}

// UnmarshalJSON parses the JSON-encoded byte slice and stores the result in the
// value pointed to by s.f. Note that this method allows for construction of a
// SortedSectorInfo which violates its invariant (that its SectorInfo are sorted
// in some defined way). Callers should take care to never provide a byte slice
// which would violate this invariant.
func (s *SortedSectorInfo) UnmarshalJSON(b []byte) error {
	return json.Unmarshal(b, &s.f)
}

71
72
type SectorInfo struct {
	SectorID uint64
73
	CommR    [CommitmentBytesLen]byte
74
75
}

76
77
78
// CommitmentBytesLen is the number of bytes in a CommR, CommD, CommP, and CommRStar.
const CommitmentBytesLen = 32

79
80
81
82
83
84
85
// 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
86
87
88
89
90
91
92
93
// 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
94
	Health    sealed_sector_health.Health
Sidney Keese's avatar
Sidney Keese committed
95
96
}

97
98
99
// SectorSealingStatus communicates how far along in the sealing process a
// sector has progressed.
type SectorSealingStatus struct {
100
101
102
103
104
105
106
107
	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
108
109
110
111
112
113
114
}

// PieceMetadata represents a piece stored by the sector builder.
type PieceMetadata struct {
	Key            string
	Size           uint64
	InclusionProof []byte
115
	CommP          [CommitmentBytesLen]byte
116
117
118
119
120
121
}

// VerifySeal returns true if the sealing operation from which its inputs were
// derived was valid, and false if not.
func VerifySeal(
	sectorSize uint64,
122
123
124
	commR [CommitmentBytesLen]byte,
	commD [CommitmentBytesLen]byte,
	commRStar [CommitmentBytesLen]byte,
125
	proverID [31]byte,
laser's avatar
laser committed
126
	sectorID uint64,
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
	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
147
	resPtr := C.sector_builder_ffi_verify_seal(
148
		C.uint64_t(sectorSize),
149
150
151
		(*[CommitmentBytesLen]C.uint8_t)(commRCBytes),
		(*[CommitmentBytesLen]C.uint8_t)(commDCBytes),
		(*[CommitmentBytesLen]C.uint8_t)(commRStarCBytes),
152
		(*[31]C.uint8_t)(proverIDCBytes),
laser's avatar
laser committed
153
		C.uint64_t(sectorID),
154
155
		(*C.uint8_t)(proofCBytes),
		C.size_t(len(proof)),
156
	)
157
158
159
160
161
162
163
164
165
166
167
168
169
	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,
170
	sectorInfo SortedSectorInfo,
laser's avatar
laser committed
171
172
	challengeSeed [32]byte,
	proof []byte,
173
174
175
176
	faults []uint64,
) (bool, error) {
	defer elapsed("VerifyPoSt")()

177
178
179
180
181
182
183
184
	// 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
	}
185
186

	// flattening the byte slice makes it easier to copy into the C heap
187
188
	flattened := make([]byte, CommitmentBytesLen*len(sortedCommRs))
	for idx, commR := range sortedCommRs {
189
		copy(flattened[(CommitmentBytesLen*idx):(CommitmentBytesLen*(1+idx))], commR[:])
190
191
192
193
194
195
196
197
198
	}

	// 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
199
200
	proofCBytes := C.CBytes(proof)
	defer C.free(proofCBytes)
201
202

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

206
207
208
209
	faultsPtr, faultsSize := cUint64s(faults)
	defer C.free(unsafe.Pointer(faultsPtr))

	// a mutable pointer to a VerifyPoStResponse C-struct
210
	resPtr := C.sector_builder_ffi_verify_post(
211
		C.uint64_t(sectorSize),
212
		(*[CommitmentBytesLen]C.uint8_t)(challengeSeedCBytes),
laser's avatar
laser committed
213
214
		sectorIdsPtr,
		sectorIdsSize,
215
216
		faultsPtr,
		faultsSize,
laser's avatar
laser committed
217
218
219
220
		(*C.uint8_t)(flattenedCommRsCBytes),
		C.size_t(len(flattened)),
		(*C.uint8_t)(proofCBytes),
		C.size_t(len(proof)),
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
	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
266
	class, err := cSectorClass(sectorSize, poRepProofPartitions)
267
268
269
270
	if err != nil {
		return nil, errors.Wrap(err, "failed to get sector class")
	}

271
	resPtr := C.sector_builder_ffi_init_sector_builder(
272
273
274
275
276
277
278
		class,
		C.uint64_t(lastUsedSectorID),
		cMetadataDir,
		(*[31]C.uint8_t)(proverIDCBytes),
		cSealedSectorDir,
		cStagedSectorDir,
		C.uint8_t(maxNumOpenStagedSectors),
279
	)
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
	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))
}

298
// AddPiece writes the given piece into an unsealed sector and returns the id of that sector.
299
300
301
func AddPiece(
	sectorBuilderPtr unsafe.Pointer,
	pieceKey string,
302
	pieceBytes uint64,
303
	piecePath string,
304
) (uint64, error) {
305
306
	defer elapsed("AddPiece")()

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
	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")()

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

327
	pieceFd := pieceFile.Fd()
328

329
330
331
332
333
334
335
336
337
338
	// 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

339
	resPtr := C.sector_builder_ffi_add_piece(
340
341
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		cPieceKey,
342
343
		C.int(pieceFd),
		C.uint64_t(pieceBytes),
344
		C.uint64_t(pieceExpiryUtcSeconds),
345
	)
346
347
	defer C.sector_builder_ffi_destroy_add_piece_response(resPtr)

348
349
350
	// Make sure our filedescriptor stays alive, stayin alive
	runtime.KeepAlive(pieceFile)

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
	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))

367
368
369
370
	resPtr := C.sector_builder_ffi_read_piece_from_sealed_sector(
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		cPieceKey,
	)
371
372
373
374
375
376
377
378
379
380
381
382
383
	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")()

384
	resPtr := C.sector_builder_ffi_seal_all_staged_sectors((*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr))
385
386
387
388
389
390
391
392
393
394
395
396
397
	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")()

398
	resPtr := C.sector_builder_ffi_get_staged_sectors((*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr))
399
400
401
402
403
404
	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))
	}

405
	meta, err := goStagedSectorMetadata(resPtr.sectors_ptr, resPtr.sectors_len)
406
407
408
409
410
411
412
	if err != nil {
		return nil, err
	}

	return meta, nil
}

413
414
415
// 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
416
417
	defer elapsed("GetAllSealedSectors")()

418
419
	return getAllSealedSectors(sectorBuilderPtr, false)
}
Sidney Keese's avatar
Sidney Keese committed
420

421
422
423
424
425
// 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
426

427
	return getAllSealedSectors(sectorBuilderPtr, true)
Sidney Keese's avatar
Sidney Keese committed
428
429
}

430
431
432
// 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.
433
434
435
func GetSectorSealingStatusByID(sectorBuilderPtr unsafe.Pointer, sectorID uint64) (SectorSealingStatus, error) {
	defer elapsed("GetSectorSealingStatusByID")()

436
437
438
439
	resPtr := C.sector_builder_ffi_get_seal_status(
		(*C.sector_builder_ffi_SectorBuilder)(sectorBuilderPtr),
		C.uint64_t(sectorID),
	)
440
441
442
443
444
445
446
	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 {
447
		return SectorSealingStatus{SectorID: sectorID, State: sealing_state.Failed, SealErrorMsg: C.GoString(resPtr.seal_error_msg)}, nil
448
	} else if resPtr.seal_status_code == C.Pending {
449
		return SectorSealingStatus{SectorID: sectorID, State: sealing_state.Pending}, nil
450
	} else if resPtr.seal_status_code == C.Sealing {
451
		return SectorSealingStatus{SectorID: sectorID, State: sealing_state.Sealing}, nil
452
	} else if resPtr.seal_status_code == C.Sealed {
453
454
		commRSlice := goBytes(&resPtr.comm_r[0], CommitmentBytesLen)
		var commR [CommitmentBytesLen]byte
455
456
		copy(commR[:], commRSlice)

457
458
		commDSlice := goBytes(&resPtr.comm_d[0], CommitmentBytesLen)
		var commD [CommitmentBytesLen]byte
459
460
		copy(commD[:], commDSlice)

461
462
		commRStarSlice := goBytes(&resPtr.comm_r_star[0], CommitmentBytesLen)
		var commRStar [CommitmentBytesLen]byte
463
464
465
466
467
468
469
470
471
472
		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{
473
474
475
476
477
478
479
			SectorID:  sectorID,
			State:     sealing_state.Sealed,
			CommD:     commD,
			CommR:     commR,
			CommRStar: commRStar,
			Proof:     proof,
			Pieces:    ps,
480
481
482
483
484
485
486
487
488
489
		}, 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,
490
	sectorInfo SortedSectorInfo,
491
	challengeSeed [CommitmentBytesLen]byte,
laser's avatar
laser committed
492
493
	faults []uint64,
) ([]byte, error) {
494
495
	defer elapsed("GeneratePoSt")()

496
497
498
499
500
501
502
	// 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
	}

503
	// flattening the byte slice makes it easier to copy into the C heap
504
505
	flattened := make([]byte, CommitmentBytesLen*len(sortedCommRs))
	for idx, commR := range sortedCommRs {
506
		copy(flattened[(CommitmentBytesLen*idx):(CommitmentBytesLen*(1+idx))], commR[:])
507
508
509
510
511
512
513
514
	}

	// 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
515
516
517
	faultsPtr, faultsSize := cUint64s(faults)
	defer C.free(unsafe.Pointer(faultsPtr))

518
	// a mutable pointer to a GeneratePoStResponse C-struct
519
520
521
522
523
	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
524
525
		faultsPtr,
		faultsSize,
526
	)
527
528
529
	defer C.sector_builder_ffi_destroy_generate_post_response(resPtr)

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

laser's avatar
laser committed
533
	return goBytes(resPtr.proof_ptr, resPtr.proof_len), nil
534
}
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565

// 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
566
567
568
569
570
571
// 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
	}
572

573
574
575
576
577
578
579
580
581
	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))
582
583
	defer C.sector_builder_ffi_destroy_generate_piece_commitment_response(resPtr)

584
585
586
	// Make sure our filedescriptor stays alive, stayin alive
	runtime.KeepAlive(pieceFile)

587
588
589
590
591
592
593
594
595
596
	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
}
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612

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
}