sealer: Support external PC2 executor commands

This commit is contained in:
Łukasz Magiera 2023-08-18 16:53:59 +02:00
parent dfd32620b1
commit fac122c358
4 changed files with 175 additions and 6 deletions

View File

@ -305,7 +305,36 @@ var simplePreCommit2 = &cli.Command{
Name: "synthetic",
Usage: "generate synthetic PoRep proofs",
},
&cli.StringFlag{
Name: "external-pc2",
Usage: "command for computing PC2 externally",
},
},
Description: `Compute PreCommit2 inputs and seal a sector.
--external-pc2 can be used to compute the PreCommit2 inputs externally.
The flag behaves similarly to the related lotus-worker flag, using it in
lotus-bench may be useful for testing if the external PreCommit2 command is
invoked correctly.
The command will be called with a number of environment variables set:
* EXTSEAL_PC2_SECTOR_NUM: the sector number
* EXTSEAL_PC2_SECTOR_MINER: the miner id
* EXTSEAL_PC2_PROOF_TYPE: the proof type
* EXTSEAL_PC2_SECTOR_SIZE: the sector size in bytes
* EXTSEAL_PC2_CACHE: the path to the cache directory
* EXTSEAL_PC2_SEALED: the path to the sealed sector file (initialized with unsealed data by the caller)
* EXTSEAL_PC2_PC1OUT: output from rust-fil-proofs precommit1 phase (base64 encoded json)
The command is expected to:
* Create cache sc-02-data-tree-r* files
* Create cache sc-02-data-tree-c* files
* Create cache p_aux / t_aux files
* Transform the sealed file in place
Example invocation of lotus-bench as external executor:
'./lotus-bench simple precommit2 --sector-size $EXTSEAL_PC2_SECTOR_SIZE $EXTSEAL_PC2_SEALED $EXTSEAL_PC2_CACHE $EXTSEAL_PC2_PC1OUT'
`,
ArgsUsage: "[sealed] [cache] [pc1 out]",
Action: func(cctx *cli.Context) error {
ctx := cctx.Context
@ -330,7 +359,18 @@ var simplePreCommit2 = &cli.Command{
storiface.FTSealed: cctx.Args().Get(0),
storiface.FTCache: cctx.Args().Get(1),
}
sealer, err := ffiwrapper.New(pp)
var opts []ffiwrapper.FFIWrapperOpt
if cctx.IsSet("external-pc2") {
extSeal := ffiwrapper.ExternalSealer{
PreCommit2: ffiwrapper.MakeExternPrecommit2(cctx.String("external-pc2")),
}
opts = append(opts, ffiwrapper.WithExternalSealCalls(extSeal))
}
sealer, err := ffiwrapper.New(pp, opts...)
if err != nil {
return err
}

View File

@ -0,0 +1,87 @@
package ffiwrapper
import (
"context"
"encoding/base64"
"fmt"
commcid "github.com/filecoin-project/go-fil-commcid"
"github.com/filecoin-project/lotus/storage/sealer/commitment"
"golang.org/x/xerrors"
"os"
"os/exec"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
// MakeExternPrecommit2 creates an implementation of ExternPrecommit2 backed by
// an external command specified by the command string.
//
// The command will be called with a number of environment variables set:
// * EXTSEAL_PC2_SECTOR_NUM: the sector number
// * EXTSEAL_PC2_SECTOR_MINER: the miner id
// * EXTSEAL_PC2_PROOF_TYPE: the proof type
// * EXTSEAL_PC2_SECTOR_SIZE: the sector size in bytes
// * EXTSEAL_PC2_CACHE: the path to the cache directory
// * EXTSEAL_PC2_SEALED: the path to the sealed sector file (initialized with unsealed data by the caller)
// * EXTSEAL_PC2_PC1OUT: output from rust-fil-proofs precommit1 phase (base64 encoded json)
//
// The command is expected to:
// * Create cache sc-02-data-tree-r* files
// * Create cache sc-02-data-tree-c* files
// * Create cache p_aux / t_aux files
// * Transform the sealed file in place
func MakeExternPrecommit2(command string) ExternPrecommit2 {
return func(ctx context.Context, sector storiface.SectorRef, cache, sealed string, pc1out storiface.PreCommit1Out) (sealedCID cid.Cid, unsealedCID cid.Cid, err error) {
ssize, err := sector.ProofType.SectorSize()
if err != nil {
return cid.Undef, cid.Undef, err
}
// Set environment variables for the external command
env := []string{
"EXTSEAL_PC2_SECTOR_NUM=" + sector.ID.Number.String(),
"EXTSEAL_PC2_SECTOR_MINER=" + sector.ID.Miner.String(),
"EXTSEAL_PC2_PROOF_TYPE=" + fmt.Sprintf("%d", sector.ProofType),
"EXTSEAL_PC2_SECTOR_SIZE=" + fmt.Sprintf("%d", ssize),
"EXTSEAL_PC2_CACHE=" + cache,
"EXTSEAL_PC2_SEALED=" + sealed,
"EXTSEAL_PC2_PC1OUT=" + base64.StdEncoding.EncodeToString(pc1out),
}
log.Infow("running external sealing call", "method", "precommit2", "command", command, "env", env)
// Create and run the external command
cmd := exec.CommandContext(ctx, "sh", "-c", command)
cmd.Env = env
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return cid.Cid{}, cid.Cid{}, xerrors.Errorf("external command error: %w", err)
}
commr, err := commitment.PAuxCommR(cache)
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("reading p_aux: %w", err)
}
sealedCID, err = commcid.ReplicaCommitmentV1ToCID(commr[:])
if err != nil {
return cid.Cid{}, cid.Cid{}, err
}
commd, err := commitment.TreeDCommD(cache)
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("reading CommD from tree-d: %w", err)
}
unsealedCID, err = commcid.DataCommitmentV1ToCID(commd[:])
if err != nil {
return cid.Cid{}, cid.Cid{}, err
}
return sealedCID, unsealedCID, nil
}
}

View File

@ -1,13 +1,26 @@
package ffiwrapper
import (
"context"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
)
var log = logging.Logger("ffiwrapper")
type ExternPrecommit2 func(ctx context.Context, sector storiface.SectorRef, cache, sealed string, pc1out storiface.PreCommit1Out) (sealedCID cid.Cid, unsealedCID cid.Cid, err error)
type ExternalSealer struct {
PreCommit2 ExternPrecommit2
}
type Sealer struct {
sectors SectorProvider
sectors SectorProvider
// externCalls cointain overrides for calling alternative sealing logic
externCalls ExternalSealer
stopping chan struct{}
}

View File

@ -40,10 +40,30 @@ import (
var _ storiface.Storage = &Sealer{}
func New(sectors SectorProvider) (*Sealer, error) {
type FFIWrapperOpts struct {
ext ExternalSealer
}
type FFIWrapperOpt func(*FFIWrapperOpts)
func WithExternalSealCalls(ext ExternalSealer) FFIWrapperOpt {
return func(o *FFIWrapperOpts) {
o.ext = ext
}
}
func New(sectors SectorProvider, opts ...FFIWrapperOpt) (*Sealer, error) {
options := &FFIWrapperOpts{}
for _, o := range opts {
o(options)
}
sb := &Sealer{
sectors: sectors,
externCalls: options.ext,
stopping: make(chan struct{}),
}
@ -881,9 +901,18 @@ func (sb *Sealer) SealPreCommit2(ctx context.Context, sector storiface.SectorRef
}
defer done()
sealedCID, unsealedCID, err := ffi.SealPreCommitPhase2(phase1Out, paths.Cache, paths.Sealed)
if err != nil {
return storiface.SectorCids{}, xerrors.Errorf("presealing sector %d (%s): %w", sector.ID.Number, paths.Unsealed, err)
var sealedCID, unsealedCID cid.Cid
if sb.externCalls.PreCommit2 == nil {
sealedCID, unsealedCID, err = ffi.SealPreCommitPhase2(phase1Out, paths.Cache, paths.Sealed)
if err != nil {
return storiface.SectorCids{}, xerrors.Errorf("presealing sector %d (%s): %w", sector.ID.Number, paths.Unsealed, err)
}
} else {
sealedCID, unsealedCID, err = sb.externCalls.PreCommit2(ctx, sector, paths.Cache, paths.Sealed, phase1Out)
if err != nil {
return storiface.SectorCids{}, xerrors.Errorf("presealing sector (extern-pc2) %d (%s): %w", sector.ID.Number, paths.Unsealed, err)
}
}
ssize, err := sector.ProofType.SectorSize()