Skip to content

Commit

Permalink
chore: ffi: copy verifier iface, mock & ffi out of storage (filecoin-…
Browse files Browse the repository at this point in the history
…project#11581)

* chore: copy verifier iface, mock & ffi out of storage

one step toward a cleaner separation of miner & chain

* ffi: s/verifier/proofs, incorporate GenerateUnsealedCID

* fix: ffi: use non-ffi version of GenerateUnsealedCID

* doc: proofs: document GenerateUnsealedCID use
  • Loading branch information
rvagg authored and ribasushi committed Aug 20, 2024
1 parent 94c9cec commit 4499245
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 54 deletions.
11 changes: 6 additions & 5 deletions chain/consensus/filcns/filecoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ import (
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/proofs"
proofsffi "github.com/filecoin-project/lotus/chain/proofs/ffi"
"github.com/filecoin-project/lotus/chain/rand"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/lib/async"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)

var log = logging.Logger("fil-consensus")
Expand All @@ -52,7 +52,7 @@ type FilecoinEC struct {
// the state manager handles making state queries
sm *stmgr.StateManager

verifier storiface.Verifier
verifier proofs.Verifier

genesis *types.TipSet
}
Expand Down Expand Up @@ -96,7 +96,7 @@ var RewardFunc = func(ctx context.Context, vmi vm.Interface, em stmgr.ExecMonito
return nil
}

func NewFilecoinExpectedConsensus(sm *stmgr.StateManager, beacon beacon.Schedule, verifier storiface.Verifier, genesis chain.Genesis) consensus.Consensus {
func NewFilecoinExpectedConsensus(sm *stmgr.StateManager, beacon beacon.Schedule, verifier proofs.Verifier, genesis chain.Genesis) consensus.Consensus {
if build.InsecurePoStValidation {
log.Warn("*********************************************************************************************")
log.Warn(" [INSECURE-POST-VALIDATION] Insecure test validation is enabled. If you see this outside of a test, it is a severe bug! ")
Expand Down Expand Up @@ -369,7 +369,8 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.
}
}

ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, proof.WinningPoStVerifyInfo{
// TODO(rvagg): why is this using proofsffi.ProofVerifier.VerifyWinningPoSt directly and not filec.verifier.VerifyWinningPoSt?
ok, err := proofsffi.ProofVerifier.VerifyWinningPoSt(ctx, proof.WinningPoStVerifyInfo{
Randomness: rand,
Proofs: h.WinPoStProof,
ChallengedSectors: sectors,
Expand Down
10 changes: 5 additions & 5 deletions chain/gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import (
"github.com/filecoin-project/lotus/chain/consensus/filcns"
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
"github.com/filecoin-project/lotus/chain/index"
"github.com/filecoin-project/lotus/chain/proofs"
proofsffi "github.com/filecoin-project/lotus/chain/proofs/ffi"
"github.com/filecoin-project/lotus/chain/rand"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
Expand All @@ -46,8 +48,6 @@ import (
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/journal"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)

const msgsPerBlock = 20
Expand Down Expand Up @@ -350,7 +350,7 @@ func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
}

func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round abi.ChainEpoch) ([]types.BeaconEntry, *types.ElectionProof, *types.Ticket, error) {
mc := &mca{w: cg.w, sm: cg.sm, pv: ffiwrapper.ProofVerifier, bcn: cg.beacon}
mc := &mca{w: cg.w, sm: cg.sm, pv: proofsffi.ProofVerifier, bcn: cg.beacon}

mbi, err := mc.MinerGetBaseInfo(ctx, m, round, pts.Key())
if err != nil {
Expand Down Expand Up @@ -603,7 +603,7 @@ type MiningCheckAPI interface {
type mca struct {
w *wallet.LocalWallet
sm *stmgr.StateManager
pv storiface.Verifier
pv proofs.Verifier
bcn beacon.Schedule
}

Expand Down Expand Up @@ -685,7 +685,7 @@ func ComputeVRF(ctx context.Context, sign SignFunc, worker address.Address, sigI

type genFakeVerifier struct{}

var _ storiface.Verifier = (*genFakeVerifier)(nil)
var _ proofs.Verifier = (*genFakeVerifier)(nil)

func (m genFakeVerifier) VerifySeal(svi proof7.SealVerifyInfo) (bool, error) {
return true, nil
Expand Down
55 changes: 55 additions & 0 deletions chain/proofs/ffi/verifier_cgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//go:build cgo
// +build cgo

package proofsffi

import (
"context"

"go.opencensus.io/trace"

ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/proof"

"github.com/filecoin-project/lotus/chain/proofs"
)

var _ proofs.Verifier = ProofVerifier

type proofVerifier struct{}

var ProofVerifier = proofVerifier{}

func (proofVerifier) VerifySeal(info proof.SealVerifyInfo) (bool, error) {
return ffi.VerifySeal(info)
}

func (proofVerifier) VerifyAggregateSeals(aggregate proof.AggregateSealVerifyProofAndInfos) (bool, error) {
return ffi.VerifyAggregateSeals(aggregate)
}

func (proofVerifier) VerifyReplicaUpdate(update proof.ReplicaUpdateInfo) (bool, error) {
return ffi.SectorUpdate.VerifyUpdateProof(update)
}

func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) {
info.Randomness[31] &= 0x3f
_, span := trace.StartSpan(ctx, "VerifyWinningPoSt")
defer span.End()

return ffi.VerifyWinningPoSt(info)
}

func (proofVerifier) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) {
info.Randomness[31] &= 0x3f
_, span := trace.StartSpan(ctx, "VerifyWindowPoSt")
defer span.End()

return ffi.VerifyWindowPoSt(info)
}

func (proofVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proofType abi.RegisteredPoStProof, minerID abi.ActorID, randomness abi.PoStRandomness, eligibleSectorCount uint64) ([]uint64, error) {
randomness[31] &= 0x3f
return ffi.GenerateWinningPoStSectorChallenge(proofType, minerID, randomness, eligibleSectorCount)
}
125 changes: 125 additions & 0 deletions chain/proofs/mock/mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package mock

import (
"bytes"
"context"
"crypto/sha256"
"fmt"

"github.com/filecoin-project/go-state-types/abi"
prooftypes "github.com/filecoin-project/go-state-types/proof"

"github.com/filecoin-project/lotus/chain/proofs"
)

var _ proofs.Verifier = MockVerifier

type mockVerifier struct{}

var MockVerifier = mockVerifier{}

func (mockVerifier) VerifySeal(svi prooftypes.SealVerifyInfo) (bool, error) {
plen, err := svi.SealProof.ProofSize()
if err != nil {
return false, err
}

if len(svi.Proof) != int(plen) {
return false, nil
}

// only the first 32 bytes, the rest are 0.
for i, b := range svi.Proof[:32] {
// unsealed+sealed-seed*ticket
if b != svi.UnsealedCID.Bytes()[i]+svi.SealedCID.Bytes()[31-i]-svi.InteractiveRandomness[i]*svi.Randomness[i] {
return false, nil
}
}

return true, nil
}

func (mockVerifier) VerifyAggregateSeals(aggregate prooftypes.AggregateSealVerifyProofAndInfos) (bool, error) {
out := make([]byte, aggLen(len(aggregate.Infos)))
for pi, svi := range aggregate.Infos {
for i := 0; i < 32; i++ {
b := svi.UnsealedCID.Bytes()[i] + svi.SealedCID.Bytes()[31-i] - svi.InteractiveRandomness[i]*svi.Randomness[i] // raw proof byte

b *= uint8(pi) // with aggregate index
out[i] += b
}
}

ok := bytes.Equal(aggregate.Proof, out)
return ok, nil
}

func (mockVerifier) VerifyReplicaUpdate(update prooftypes.ReplicaUpdateInfo) (bool, error) {
return true, nil
}

func (mockVerifier) VerifyWinningPoSt(ctx context.Context, info prooftypes.WinningPoStVerifyInfo) (bool, error) {
info.Randomness[31] &= 0x3f
return true, nil
}

func (mockVerifier) VerifyWindowPoSt(ctx context.Context, info prooftypes.WindowPoStVerifyInfo) (bool, error) {
if len(info.Proofs) != 1 {
return false, fmt.Errorf("expected 1 proof entry")
}

proof := info.Proofs[0]

expected := generateFakePoStProof(info.ChallengedSectors, info.Randomness)
if !bytes.Equal(proof.ProofBytes, expected) {
return false, fmt.Errorf("bad proof")
}
return true, nil
}

func (mockVerifier) GenerateWinningPoStSectorChallenge(ctx context.Context, proofType abi.RegisteredPoStProof, minerID abi.ActorID, randomness abi.PoStRandomness, eligibleSectorCount uint64) ([]uint64, error) {
return []uint64{0}, nil
}

func generateFakePoStProof(sectorInfo []prooftypes.SectorInfo, randomness abi.PoStRandomness) []byte {
randomness[31] &= 0x3f

hasher := sha256.New()
_, _ = hasher.Write(randomness)
for _, info := range sectorInfo {
err := info.MarshalCBOR(hasher)
if err != nil {
panic(err)
}
}
return hasher.Sum(nil)
}

func aggLen(nproofs int) int {
switch {
case nproofs <= 8:
return 11220
case nproofs <= 16:
return 14196
case nproofs <= 32:
return 17172
case nproofs <= 64:
return 20148
case nproofs <= 128:
return 23124
case nproofs <= 256:
return 26100
case nproofs <= 512:
return 29076
case nproofs <= 1024:
return 32052
case nproofs <= 2048:
return 35028
case nproofs <= 4096:
return 38004
case nproofs <= 8192:
return 40980
default:
panic("too many proofs")
}
}
79 changes: 79 additions & 0 deletions chain/proofs/proofs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package proofs

import (
"math/bits"

"github.com/ipfs/go-cid"

"github.com/filecoin-project/go-commp-utils/nonffi"
"github.com/filecoin-project/go-commp-utils/zerocomm"
"github.com/filecoin-project/go-state-types/abi"
)

// GenerateUnsealedCID generates the UnsealedCID for a sector of size determined by the proofType
// containing pieces of the specified sizes. Where there is not one piece the size of the sector, or
// zero pieces (in which case one piece can be used), it fills in the remaining space with pieces of
// the minimum size required to pad the sector.
func GenerateUnsealedCID(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
ssize, err := proofType.SectorSize()
if err != nil {
return cid.Undef, err
}

pssize := abi.PaddedPieceSize(ssize)
allPieces := make([]abi.PieceInfo, 0, len(pieces))
if len(pieces) == 0 {
allPieces = append(allPieces, abi.PieceInfo{
Size: pssize,
PieceCID: zerocomm.ZeroPieceCommitment(pssize.Unpadded()),
})
} else {
var sum abi.PaddedPieceSize

padTo := func(pads []abi.PaddedPieceSize) {
for _, p := range pads {
allPieces = append(allPieces, abi.PieceInfo{
Size: p,
PieceCID: zerocomm.ZeroPieceCommitment(p.Unpadded()),
})

sum += p
}
}

for _, p := range pieces {
ps, _ := getRequiredPadding(sum, p.Size)
padTo(ps)

allPieces = append(allPieces, p)
sum += p.Size
}

ps, _ := getRequiredPadding(sum, pssize)
padTo(ps)
}

// Next we need to generate the unsealed CID by merkleizing the pieces; even though this function
// has the same name, it does a different job and won't give us the desired results if we hadn't
// done the piece-padding first.
return nonffi.GenerateUnsealedCID(proofType, allPieces)
}

func getRequiredPadding(oldLength abi.PaddedPieceSize, newPieceLength abi.PaddedPieceSize) ([]abi.PaddedPieceSize, abi.PaddedPieceSize) {
padPieces := make([]abi.PaddedPieceSize, 0)
toFill := uint64(-oldLength % newPieceLength)

n := bits.OnesCount64(toFill)
var sum abi.PaddedPieceSize
for i := 0; i < n; i++ {
next := bits.TrailingZeros64(toFill)
psize := uint64(1) << uint(next)
toFill ^= psize

padded := abi.PaddedPieceSize(psize)
padPieces = append(padPieces, padded)
sum += padded
}

return padPieces, sum
}
Loading

0 comments on commit 4499245

Please sign in to comment.