2019-07-27 00:45:27 +00:00
|
|
|
package sectorbuilder
|
|
|
|
|
|
|
|
import (
|
2019-11-08 18:49:36 +00:00
|
|
|
"fmt"
|
2019-09-23 10:50:28 +00:00
|
|
|
"io"
|
2019-11-07 18:33:46 +00:00
|
|
|
"os"
|
2019-11-08 18:49:36 +00:00
|
|
|
"strconv"
|
|
|
|
"sync"
|
2019-07-27 00:45:27 +00:00
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
2019-11-08 18:49:36 +00:00
|
|
|
"github.com/ipfs/go-datastore"
|
2019-08-07 23:22:35 +00:00
|
|
|
logging "github.com/ipfs/go-log"
|
2019-11-04 17:36:29 +00:00
|
|
|
"golang.org/x/xerrors"
|
2019-08-06 22:04:21 +00:00
|
|
|
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/address"
|
2019-11-08 18:49:36 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
2019-07-27 00:45:27 +00:00
|
|
|
)
|
|
|
|
|
2019-11-04 17:36:29 +00:00
|
|
|
const PoStReservedWorkers = 1
|
2019-11-07 16:39:27 +00:00
|
|
|
const PoRepProofPartitions = 2
|
2019-11-04 17:36:29 +00:00
|
|
|
|
2019-11-08 18:49:36 +00:00
|
|
|
var lastSectorIdKey = datastore.NewKey("/sectorbuilder/last")
|
|
|
|
|
2019-08-07 23:22:35 +00:00
|
|
|
var log = logging.Logger("sectorbuilder")
|
|
|
|
|
2019-07-27 21:08:10 +00:00
|
|
|
type SectorSealingStatus = sectorbuilder.SectorSealingStatus
|
|
|
|
|
|
|
|
type StagedSectorMetadata = sectorbuilder.StagedSectorMetadata
|
|
|
|
|
2019-09-18 03:32:52 +00:00
|
|
|
type SortedSectorInfo = sectorbuilder.SortedSectorInfo
|
|
|
|
|
2019-09-19 14:42:50 +00:00
|
|
|
type SectorInfo = sectorbuilder.SectorInfo
|
|
|
|
|
2019-10-27 08:56:53 +00:00
|
|
|
type SealTicket = sectorbuilder.SealTicket
|
|
|
|
|
2019-10-30 18:10:29 +00:00
|
|
|
type SealSeed = sectorbuilder.SealSeed
|
|
|
|
|
2019-10-31 01:22:50 +00:00
|
|
|
type SealPreCommitOutput = sectorbuilder.SealPreCommitOutput
|
|
|
|
|
2019-10-30 18:10:29 +00:00
|
|
|
type SealCommitOutput = sectorbuilder.SealCommitOutput
|
|
|
|
|
|
|
|
type PublicPieceInfo = sectorbuilder.PublicPieceInfo
|
2019-10-27 08:56:53 +00:00
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
type RawSealPreCommitOutput = sectorbuilder.RawSealPreCommitOutput
|
|
|
|
|
2019-07-27 00:45:27 +00:00
|
|
|
const CommLen = sectorbuilder.CommitmentBytesLen
|
|
|
|
|
|
|
|
type SectorBuilder struct {
|
|
|
|
handle unsafe.Pointer
|
2019-11-08 23:20:42 +00:00
|
|
|
ds dtypes.MetadataDS
|
|
|
|
idLk sync.Mutex
|
2019-11-08 18:49:36 +00:00
|
|
|
|
2019-11-08 23:20:42 +00:00
|
|
|
ssize uint64
|
2019-11-04 17:36:29 +00:00
|
|
|
|
2019-11-05 16:38:54 +00:00
|
|
|
Miner address.Address
|
2019-11-05 17:53:19 +00:00
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
stagedDir string
|
|
|
|
sealedDir string
|
|
|
|
cacheDir string
|
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
sealLocal bool
|
2019-11-04 17:36:29 +00:00
|
|
|
rateLimit chan struct{}
|
2019-11-21 00:52:59 +00:00
|
|
|
|
|
|
|
sealTasks chan workerCall
|
|
|
|
|
|
|
|
remoteLk sync.Mutex
|
|
|
|
remotes []*remote
|
|
|
|
remoteResults map[uint64]chan<- SealRes
|
|
|
|
|
|
|
|
stopping chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type SealRes struct {
|
|
|
|
Err error `json:"omitempty"`
|
|
|
|
|
|
|
|
Proof []byte `json:"omitempty"`
|
|
|
|
Rspco RawSealPreCommitOutput `json:"omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type remote struct {
|
|
|
|
lk sync.Mutex
|
|
|
|
|
|
|
|
sealTasks chan<- WorkerTask
|
|
|
|
busy uint64
|
2019-07-27 00:45:27 +00:00
|
|
|
}
|
|
|
|
|
2019-11-04 16:47:08 +00:00
|
|
|
type Config struct {
|
|
|
|
SectorSize uint64
|
|
|
|
Miner address.Address
|
|
|
|
|
|
|
|
WorkerThreads uint8
|
|
|
|
|
2019-10-31 01:22:50 +00:00
|
|
|
CacheDir string
|
2019-07-27 00:45:27 +00:00
|
|
|
SealedDir string
|
|
|
|
StagedDir string
|
|
|
|
MetadataDir string
|
|
|
|
}
|
|
|
|
|
2019-11-08 20:30:50 +00:00
|
|
|
func New(cfg *Config, ds dtypes.MetadataDS) (*SectorBuilder, error) {
|
2019-11-21 00:52:59 +00:00
|
|
|
if cfg.WorkerThreads < PoStReservedWorkers {
|
|
|
|
return nil, xerrors.Errorf("minimum worker threads is %d, specified %d", PoStReservedWorkers, cfg.WorkerThreads)
|
2019-11-04 17:36:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 06:35:57 +00:00
|
|
|
proverId := addressToProverID(cfg.Miner)
|
2019-07-27 00:45:27 +00:00
|
|
|
|
2019-11-07 18:33:46 +00:00
|
|
|
for _, dir := range []string{cfg.StagedDir, cfg.SealedDir, cfg.CacheDir, cfg.MetadataDir} {
|
|
|
|
if err := os.Mkdir(dir, 0755); err != nil {
|
|
|
|
if os.IsExist(err) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-08 18:49:36 +00:00
|
|
|
var lastUsedID uint64
|
|
|
|
b, err := ds.Get(lastSectorIdKey)
|
|
|
|
switch err {
|
|
|
|
case nil:
|
|
|
|
i, err := strconv.ParseInt(string(b), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
lastUsedID = uint64(i)
|
|
|
|
case datastore.ErrNotFound:
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
sbp, err := sectorbuilder.InitSectorBuilder(cfg.SectorSize, PoRepProofPartitions, lastUsedID, cfg.MetadataDir, proverId, cfg.SealedDir, cfg.StagedDir, cfg.CacheDir, 16, cfg.WorkerThreads)
|
2019-07-27 00:45:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
rlimit := cfg.WorkerThreads - PoStReservedWorkers
|
|
|
|
|
|
|
|
sealLocal := rlimit > 0
|
|
|
|
|
|
|
|
if rlimit == 0 {
|
|
|
|
rlimit = 1
|
|
|
|
}
|
|
|
|
|
2019-11-08 18:49:36 +00:00
|
|
|
sb := &SectorBuilder{
|
2019-11-06 23:09:48 +00:00
|
|
|
handle: sbp,
|
2019-11-08 23:20:42 +00:00
|
|
|
ds: ds,
|
2019-11-08 18:49:36 +00:00
|
|
|
|
2019-11-08 23:20:42 +00:00
|
|
|
ssize: cfg.SectorSize,
|
2019-11-06 23:09:48 +00:00
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
stagedDir: cfg.StagedDir,
|
|
|
|
sealedDir: cfg.SealedDir,
|
|
|
|
cacheDir: cfg.CacheDir,
|
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
Miner: cfg.Miner,
|
|
|
|
|
|
|
|
sealLocal: sealLocal,
|
|
|
|
rateLimit: make(chan struct{}, rlimit),
|
|
|
|
|
|
|
|
sealTasks: make(chan workerCall),
|
|
|
|
remoteResults: map[uint64]chan<- SealRes{},
|
2019-11-08 18:49:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sb, nil
|
2019-07-27 00:45:27 +00:00
|
|
|
}
|
|
|
|
|
2019-11-12 18:05:03 +00:00
|
|
|
func (sb *SectorBuilder) RateLimit() func() {
|
2019-11-04 17:36:29 +00:00
|
|
|
if cap(sb.rateLimit) == len(sb.rateLimit) {
|
|
|
|
log.Warn("rate-limiting sectorbuilder call")
|
|
|
|
}
|
|
|
|
sb.rateLimit <- struct{}{}
|
|
|
|
|
|
|
|
return func() {
|
|
|
|
<-sb.rateLimit
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-08 18:15:13 +00:00
|
|
|
func (sb *SectorBuilder) WorkerStats() (free, reserved, total int) {
|
|
|
|
return cap(sb.rateLimit) - len(sb.rateLimit), PoStReservedWorkers, cap(sb.rateLimit) + PoStReservedWorkers
|
|
|
|
}
|
|
|
|
|
2019-10-21 11:58:41 +00:00
|
|
|
func addressToProverID(a address.Address) [32]byte {
|
|
|
|
var proverId [32]byte
|
2019-08-07 06:35:57 +00:00
|
|
|
copy(proverId[:], a.Payload())
|
|
|
|
return proverId
|
|
|
|
}
|
|
|
|
|
2019-07-27 00:45:27 +00:00
|
|
|
func (sb *SectorBuilder) Destroy() {
|
|
|
|
sectorbuilder.DestroySectorBuilder(sb.handle)
|
|
|
|
}
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
func (sb *SectorBuilder) AcquireSectorId() (uint64, error) {
|
2019-11-08 18:49:36 +00:00
|
|
|
sb.idLk.Lock()
|
|
|
|
defer sb.idLk.Unlock()
|
|
|
|
|
|
|
|
id, err := sectorbuilder.AcquireSectorId(sb.handle)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
err = sb.ds.Put(lastSectorIdKey, []byte(fmt.Sprint(id)))
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return id, nil
|
2019-11-07 16:39:27 +00:00
|
|
|
}
|
|
|
|
|
2019-11-07 20:40:46 +00:00
|
|
|
func (sb *SectorBuilder) AddPiece(pieceSize uint64, sectorId uint64, file io.Reader, existingPieceSizes []uint64) (PublicPieceInfo, error) {
|
2019-11-20 17:28:14 +00:00
|
|
|
ret := sb.RateLimit()
|
|
|
|
defer ret()
|
|
|
|
|
2019-09-23 10:50:28 +00:00
|
|
|
f, werr, err := toReadableFile(file, int64(pieceSize))
|
|
|
|
if err != nil {
|
2019-11-07 16:39:27 +00:00
|
|
|
return PublicPieceInfo{}, err
|
2019-09-23 10:50:28 +00:00
|
|
|
}
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
stagedFile, err := sb.stagedSectorFile(sectorId)
|
2019-09-23 10:50:28 +00:00
|
|
|
if err != nil {
|
2019-11-07 16:39:27 +00:00
|
|
|
return PublicPieceInfo{}, err
|
|
|
|
}
|
|
|
|
|
2019-11-07 20:40:46 +00:00
|
|
|
_, _, commP, err := sectorbuilder.StandaloneWriteWithAlignment(f, pieceSize, stagedFile, existingPieceSizes)
|
2019-11-07 16:39:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return PublicPieceInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := stagedFile.Close(); err != nil {
|
|
|
|
return PublicPieceInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := f.Close(); err != nil {
|
|
|
|
return PublicPieceInfo{}, err
|
2019-09-23 10:50:28 +00:00
|
|
|
}
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
return PublicPieceInfo{
|
|
|
|
Size: pieceSize,
|
|
|
|
CommP: commP,
|
|
|
|
}, werr()
|
2019-07-27 00:45:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: should *really really* return an io.ReadCloser
|
|
|
|
func (sb *SectorBuilder) ReadPieceFromSealedSector(pieceKey string) ([]byte, error) {
|
2019-11-12 18:05:03 +00:00
|
|
|
ret := sb.RateLimit()
|
2019-11-04 17:36:29 +00:00
|
|
|
defer ret()
|
|
|
|
|
2019-07-27 00:45:27 +00:00
|
|
|
return sectorbuilder.ReadPieceFromSealedSector(sb.handle, pieceKey)
|
|
|
|
}
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
func (sb *SectorBuilder) SealPreCommit(sectorID uint64, ticket SealTicket, pieces []PublicPieceInfo) (RawSealPreCommitOutput, error) {
|
2019-11-12 18:05:03 +00:00
|
|
|
ret := sb.RateLimit()
|
2019-11-04 17:36:29 +00:00
|
|
|
defer ret()
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
cacheDir, err := sb.sectorCacheDir(sectorID)
|
|
|
|
if err != nil {
|
|
|
|
return RawSealPreCommitOutput{}, err
|
|
|
|
}
|
2019-10-31 01:22:50 +00:00
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
sealedPath, err := sb.SealedSectorPath(sectorID)
|
2019-11-07 16:39:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return RawSealPreCommitOutput{}, err
|
|
|
|
}
|
2019-11-04 17:36:29 +00:00
|
|
|
|
2019-11-07 19:54:24 +00:00
|
|
|
var sum uint64
|
|
|
|
for _, piece := range pieces {
|
|
|
|
sum += piece.Size
|
|
|
|
}
|
|
|
|
ussize := UserBytesForSectorSize(sb.ssize)
|
|
|
|
if sum != ussize {
|
2019-11-07 20:40:46 +00:00
|
|
|
return RawSealPreCommitOutput{}, xerrors.Errorf("aggregated piece sizes don't match sector size: %d != %d (%d)", sum, ussize, int64(ussize-sum))
|
2019-11-07 19:54:24 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
stagedPath := sb.StagedSectorPath(sectorID)
|
2019-11-07 19:54:24 +00:00
|
|
|
|
|
|
|
rspco, err := sectorbuilder.StandaloneSealPreCommit(
|
2019-11-07 16:39:27 +00:00
|
|
|
sb.ssize,
|
|
|
|
PoRepProofPartitions,
|
|
|
|
cacheDir,
|
2019-11-07 19:54:24 +00:00
|
|
|
stagedPath,
|
2019-11-07 16:39:27 +00:00
|
|
|
sealedPath,
|
|
|
|
sectorID,
|
|
|
|
addressToProverID(sb.Miner),
|
|
|
|
ticket.TicketBytes,
|
|
|
|
pieces,
|
|
|
|
)
|
2019-11-07 19:54:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return RawSealPreCommitOutput{}, xerrors.Errorf("presealing sector %d (%s): %w", sectorID, stagedPath, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return rspco, nil
|
2019-07-27 00:45:27 +00:00
|
|
|
}
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
func (sb *SectorBuilder) SealCommit(sectorID uint64, ticket SealTicket, seed SealSeed, pieces []PublicPieceInfo, pieceKeys []string, rspco RawSealPreCommitOutput) (proof []byte, err error) {
|
2019-11-12 18:05:03 +00:00
|
|
|
ret := sb.RateLimit()
|
2019-11-04 17:36:29 +00:00
|
|
|
defer ret()
|
|
|
|
|
2019-11-07 16:39:27 +00:00
|
|
|
cacheDir, err := sb.sectorCacheDir(sectorID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
proof, err = sectorbuilder.StandaloneSealCommit(
|
|
|
|
sb.ssize,
|
|
|
|
PoRepProofPartitions,
|
|
|
|
cacheDir,
|
|
|
|
sectorID,
|
|
|
|
addressToProverID(sb.Miner),
|
|
|
|
ticket.TicketBytes,
|
|
|
|
seed.TicketBytes,
|
|
|
|
pieces,
|
|
|
|
rspco,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("StandaloneSealCommit: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pmeta := make([]sectorbuilder.PieceMetadata, len(pieces))
|
|
|
|
for i, piece := range pieces {
|
|
|
|
pmeta[i] = sectorbuilder.PieceMetadata{
|
|
|
|
Key: pieceKeys[i],
|
|
|
|
Size: piece.Size,
|
|
|
|
CommP: piece.CommP,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
sealedPath, err := sb.SealedSectorPath(sectorID)
|
2019-11-07 16:39:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = sectorbuilder.ImportSealedSector(
|
|
|
|
sb.handle,
|
|
|
|
sectorID,
|
|
|
|
cacheDir,
|
|
|
|
sealedPath,
|
|
|
|
ticket,
|
|
|
|
seed,
|
|
|
|
rspco.CommR,
|
|
|
|
rspco.CommD,
|
|
|
|
rspco.CommC,
|
|
|
|
rspco.CommRLast,
|
|
|
|
proof,
|
|
|
|
pmeta,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("ImportSealedSector: %w", err)
|
|
|
|
}
|
|
|
|
return proof, nil
|
2019-10-29 22:19:58 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 00:52:59 +00:00
|
|
|
func (sb *SectorBuilder) Stop() {
|
|
|
|
close(sb.stopping)
|
2019-11-01 03:57:10 +00:00
|
|
|
}
|