lotus/cmd/lotus-seed/seed/seed.go
2022-10-06 11:06:21 -04:00

277 lines
7.3 KiB
Go

package seed
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/google/uuid"
logging "github.com/ipfs/go-log/v2"
ic "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/minio/blake2b-simd"
"golang.org/x/xerrors"
ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-commp-utils/zerocomm"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
markettypes "github.com/filecoin-project/go-state-types/builtin/v9/market"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/storage/paths"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper/basicfs"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
var log = logging.Logger("preseal")
func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.SectorNumber, sectors int, sbroot string, preimage []byte, ki *types.KeyInfo, fakeSectors bool) (*genesis.Miner, *types.KeyInfo, error) {
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, nil, err
}
if err := os.MkdirAll(sbroot, 0775); err != nil { //nolint:gosec
return nil, nil, err
}
next := offset
sbfs := &basicfs.Provider{
Root: sbroot,
}
sb, err := ffiwrapper.New(sbfs)
if err != nil {
return nil, nil, err
}
ssize, err := spt.SectorSize()
if err != nil {
return nil, nil, err
}
var sealedSectors []*genesis.PreSeal
for i := 0; i < sectors; i++ {
sid := abi.SectorID{Miner: abi.ActorID(mid), Number: next}
ref := storiface.SectorRef{ID: sid, ProofType: spt}
next++
var preseal *genesis.PreSeal
if !fakeSectors {
preseal, err = presealSector(sb, sbfs, ref, ssize, preimage)
if err != nil {
return nil, nil, err
}
} else {
preseal, err = presealSectorFake(sbfs, ref, ssize)
if err != nil {
return nil, nil, err
}
}
sealedSectors = append(sealedSectors, preseal)
}
var minerAddr *key.Key
if ki != nil {
minerAddr, err = key.NewKey(*ki)
if err != nil {
return nil, nil, err
}
} else {
minerAddr, err = key.GenerateKey(types.KTBLS)
if err != nil {
return nil, nil, err
}
}
var pid peer.ID
{
log.Warn("PeerID not specified, generating dummy")
p, _, err := ic.GenerateEd25519Key(rand.Reader)
if err != nil {
return nil, nil, err
}
pid, err = peer.IDFromPrivateKey(p)
if err != nil {
return nil, nil, err
}
}
miner := &genesis.Miner{
ID: maddr,
Owner: minerAddr.Address,
Worker: minerAddr.Address,
MarketBalance: big.Zero(),
PowerBalance: big.Zero(),
SectorSize: ssize,
Sectors: sealedSectors,
PeerId: pid,
}
if err := createDeals(miner, minerAddr, maddr, ssize); err != nil {
return nil, nil, xerrors.Errorf("creating deals: %w", err)
}
{
b, err := json.MarshalIndent(&paths.LocalStorageMeta{
ID: storiface.ID(uuid.New().String()),
Weight: 0, // read-only
CanSeal: false,
CanStore: false,
}, "", " ")
if err != nil {
return nil, nil, xerrors.Errorf("marshaling storage config: %w", err)
}
if err := ioutil.WriteFile(filepath.Join(sbroot, "sectorstore.json"), b, 0644); err != nil {
return nil, nil, xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(sbroot, "storage.json"), err)
}
}
return miner, &minerAddr.KeyInfo, nil
}
func presealSector(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, sid storiface.SectorRef, ssize abi.SectorSize, preimage []byte) (*genesis.PreSeal, error) {
pi, err := sb.AddPiece(context.TODO(), sid, nil, abi.PaddedPieceSize(ssize).Unpadded(), rand.Reader)
if err != nil {
return nil, err
}
trand := blake2b.Sum256(preimage)
ticket := abi.SealRandomness(trand[:])
fmt.Printf("sector-id: %d, piece info: %v\n", sid, pi)
in2, err := sb.SealPreCommit1(context.TODO(), sid, ticket, []abi.PieceInfo{pi})
if err != nil {
return nil, xerrors.Errorf("commit: %w", err)
}
cids, err := sb.SealPreCommit2(context.TODO(), sid, in2)
if err != nil {
return nil, xerrors.Errorf("commit: %w", err)
}
if err := sb.FinalizeSector(context.TODO(), sid, nil); err != nil {
return nil, xerrors.Errorf("trim cache: %w", err)
}
if err := cleanupUnsealed(sbfs, sid); err != nil {
return nil, xerrors.Errorf("remove unsealed file: %w", err)
}
log.Warn("PreCommitOutput: ", sid, cids.Sealed, cids.Unsealed)
return &genesis.PreSeal{
CommR: cids.Sealed,
CommD: cids.Unsealed,
SectorID: sid.ID.Number,
ProofType: sid.ProofType,
}, nil
}
func presealSectorFake(sbfs *basicfs.Provider, sid storiface.SectorRef, ssize abi.SectorSize) (*genesis.PreSeal, error) {
paths, done, err := sbfs.AcquireSector(context.TODO(), sid, 0, storiface.FTSealed|storiface.FTCache, storiface.PathSealing)
if err != nil {
return nil, xerrors.Errorf("acquire unsealed sector: %w", err)
}
defer done()
if err := os.Mkdir(paths.Cache, 0755); err != nil {
return nil, xerrors.Errorf("mkdir cache: %w", err)
}
commr, err := ffi.FauxRep(sid.ProofType, paths.Cache, paths.Sealed)
if err != nil {
return nil, xerrors.Errorf("fauxrep: %w", err)
}
return &genesis.PreSeal{
CommR: commr,
CommD: zerocomm.ZeroPieceCommitment(abi.PaddedPieceSize(ssize).Unpadded()),
SectorID: sid.ID.Number,
ProofType: sid.ProofType,
}, nil
}
func cleanupUnsealed(sbfs *basicfs.Provider, ref storiface.SectorRef) error {
paths, done, err := sbfs.AcquireSector(context.TODO(), ref, storiface.FTUnsealed, storiface.FTNone, storiface.PathSealing)
if err != nil {
return err
}
defer done()
return os.Remove(paths.Unsealed)
}
func WriteGenesisMiner(maddr address.Address, sbroot string, gm *genesis.Miner, key *types.KeyInfo) error {
output := map[string]genesis.Miner{
maddr.String(): *gm,
}
out, err := json.MarshalIndent(output, "", " ")
if err != nil {
return err
}
log.Infof("Writing preseal manifest to %s", filepath.Join(sbroot, "pre-seal-"+maddr.String()+".json"))
if err := ioutil.WriteFile(filepath.Join(sbroot, "pre-seal-"+maddr.String()+".json"), out, 0664); err != nil {
return err
}
if key != nil {
b, err := json.Marshal(key)
if err != nil {
return err
}
// TODO: allow providing key
if err := ioutil.WriteFile(filepath.Join(sbroot, "pre-seal-"+maddr.String()+".key"), []byte(hex.EncodeToString(b)), 0664); err != nil {
return err
}
}
return nil
}
func createDeals(m *genesis.Miner, k *key.Key, maddr address.Address, ssize abi.SectorSize) error {
for i, sector := range m.Sectors {
label, err := markettypes.NewLabelFromString(fmt.Sprintf("%d", i))
if err != nil {
return xerrors.Errorf("error creating deal label: %w", err)
}
proposal := &markettypes.DealProposal{
PieceCID: sector.CommD,
PieceSize: abi.PaddedPieceSize(ssize),
Client: k.Address,
Provider: maddr,
Label: label,
StartEpoch: 0,
EndEpoch: 9001,
StoragePricePerEpoch: big.Zero(),
ProviderCollateral: big.Zero(),
ClientCollateral: big.Zero(),
}
sector.DealClientKey = &k.KeyInfo
sector.Deal = *proposal
}
return nil
}