lotus/storage/sbmock/sbmock.go

360 lines
8.5 KiB
Go
Raw Normal View History

package sbmock
import (
"bytes"
2020-01-09 18:28:14 +00:00
"context"
2020-01-09 19:23:42 +00:00
"fmt"
"io"
"io/ioutil"
2020-01-13 20:47:27 +00:00
"math/big"
"math/rand"
"sync"
2020-02-26 22:54:34 +00:00
commcid "github.com/filecoin-project/go-fil-commcid"
"github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/specs-actors/actors/abi"
2020-02-26 22:54:34 +00:00
"github.com/ipfs/go-cid"
2020-03-02 01:09:38 +00:00
logging "github.com/ipfs/go-log"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
ffi "github.com/filecoin-project/filecoin-ffi"
)
2020-03-02 01:09:38 +00:00
var log = logging.Logger("sbmock")
type SBMock struct {
sectors map[abi.SectorNumber]*sectorState
sectorSize abi.SectorSize
nextSectorID abi.SectorNumber
rateLimit chan struct{}
2020-03-02 01:09:38 +00:00
proofType abi.RegisteredProof
lk sync.Mutex
}
2020-01-14 02:04:33 +00:00
type mockVerif struct{}
2020-01-13 20:47:27 +00:00
func NewMockSectorBuilder(threads int, ssize abi.SectorSize) *SBMock {
2020-03-02 01:09:38 +00:00
rt, _, err := api.ProofTypeFromSectorSize(ssize)
if err != nil {
panic(err)
}
return &SBMock{
sectors: make(map[abi.SectorNumber]*sectorState),
sectorSize: ssize,
2020-01-13 20:47:27 +00:00
nextSectorID: 5,
rateLimit: make(chan struct{}, threads),
2020-03-02 01:09:38 +00:00
proofType: rt,
}
}
2020-01-09 19:23:42 +00:00
const (
statePacking = iota
statePreCommit
stateCommit
)
type sectorState struct {
2020-02-26 22:54:34 +00:00
pieces []cid.Cid
2020-01-09 19:23:42 +00:00
failed bool
state int
lk sync.Mutex
}
func (sb *SBMock) RateLimit() func() {
sb.rateLimit <- struct{}{}
// TODO: probably want to copy over rate limit code
return func() {
<-sb.rateLimit
}
}
2020-02-26 22:54:34 +00:00
func (sb *SBMock) AddPiece(ctx context.Context, size abi.UnpaddedPieceSize, sectorId abi.SectorNumber, r io.Reader, existingPieces []abi.UnpaddedPieceSize) (abi.PieceInfo, error) {
2020-03-02 01:09:38 +00:00
log.Warn("Add piece: ", sectorId, size, sb.proofType)
sb.lk.Lock()
ss, ok := sb.sectors[sectorId]
if !ok {
2020-01-09 19:23:42 +00:00
ss = &sectorState{
state: statePacking,
}
sb.sectors[sectorId] = ss
}
2020-01-09 19:23:42 +00:00
sb.lk.Unlock()
ss.lk.Lock()
defer ss.lk.Unlock()
2020-03-02 01:09:38 +00:00
c, err := sectorbuilder.GeneratePieceCIDFromFile(sb.proofType, r, size)
if err != nil {
2020-03-02 01:09:38 +00:00
return abi.PieceInfo{}, xerrors.Errorf("failed to generate piece cid: %w", err)
}
2020-03-02 01:09:38 +00:00
log.Warn("Generated Piece CID: ", c)
2020-02-26 22:54:34 +00:00
ss.pieces = append(ss.pieces, c)
return abi.PieceInfo{
2020-02-27 00:42:39 +00:00
Size: size.Padded(),
2020-02-26 22:54:34 +00:00
PieceCID: c,
}, nil
}
func (sb *SBMock) SectorSize() abi.SectorSize {
return sb.sectorSize
}
2020-02-11 01:23:03 +00:00
func (sb *SBMock) AcquireSectorNumber() (abi.SectorNumber, error) {
sb.lk.Lock()
2020-01-09 19:23:42 +00:00
defer sb.lk.Unlock()
id := sb.nextSectorID
sb.nextSectorID++
return id, nil
}
2020-02-26 22:54:34 +00:00
func (sb *SBMock) GenerateFallbackPoSt([]abi.SectorInfo, abi.PoStRandomness, []abi.SectorNumber) ([]ffi.PoStCandidateWithTicket, []abi.PoStProof, error) {
panic("NYI")
}
func (sb *SBMock) SealPreCommit1(ctx context.Context, sid abi.SectorNumber, ticket abi.SealRandomness, pieces []abi.PieceInfo) (out []byte, err error) {
2020-01-09 19:23:42 +00:00
sb.lk.Lock()
ss, ok := sb.sectors[sid]
sb.lk.Unlock()
if !ok {
return nil, xerrors.Errorf("no sector with id %d in sectorbuilder", sid)
}
2020-01-09 19:23:42 +00:00
ss.lk.Lock()
defer ss.lk.Unlock()
2020-02-21 19:28:01 +00:00
ussize := abi.PaddedPieceSize(sb.sectorSize).Unpadded()
// TODO: verify pieces in sinfo.pieces match passed in pieces
var sum abi.UnpaddedPieceSize
for _, p := range pieces {
2020-02-26 22:54:34 +00:00
sum += p.Size.Unpadded()
}
if sum != ussize {
return nil, xerrors.Errorf("aggregated piece sizes don't match up: %d != %d", sum, ussize)
}
2020-01-09 19:23:42 +00:00
if ss.state != statePacking {
return nil, xerrors.Errorf("cannot call pre-seal on sector not in 'packing' state")
2020-01-09 19:23:42 +00:00
}
opFinishWait(ctx)
2020-01-09 19:23:42 +00:00
ss.state = statePreCommit
2020-02-26 22:54:34 +00:00
pis := make([]abi.PieceInfo, len(ss.pieces))
2020-01-13 20:47:27 +00:00
for i, piece := range ss.pieces {
2020-02-26 22:54:34 +00:00
pis[i] = abi.PieceInfo{
2020-02-27 00:42:39 +00:00
Size: pieces[i].Size,
2020-02-26 22:54:34 +00:00
PieceCID: piece,
2020-01-13 20:47:27 +00:00
}
}
commd, err := MockVerifier.GenerateDataCommitment(abi.PaddedPieceSize(sb.sectorSize), pis)
2020-01-13 20:47:27 +00:00
if err != nil {
return nil, err
2020-01-13 20:47:27 +00:00
}
2020-02-26 22:54:34 +00:00
cc, _, err := commcid.CIDToCommitment(commd)
if err != nil {
panic(err)
}
2020-02-27 00:42:39 +00:00
cc[0] ^= 'd'
return cc, nil
}
func (sb *SBMock) SealPreCommit2(ctx context.Context, sid abi.SectorNumber, phase1Out []byte) (sealedCID cid.Cid, unsealedCID cid.Cid, err error) {
db := []byte(string(phase1Out))
db[0] ^= 'd'
d := commcid.DataCommitmentV1ToCID(db)
2020-02-27 00:42:39 +00:00
2020-02-26 22:54:34 +00:00
commr := make([]byte, 32)
for i := range db {
commr[32-(i+1)] = db[i]
2020-02-26 22:54:34 +00:00
}
commR := commcid.DataCommitmentV1ToCID(commr)
return commR, d, nil
}
func (sb *SBMock) SealCommit1(ctx context.Context, sid abi.SectorNumber, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, sealedCid cid.Cid, unsealed cid.Cid) (output []byte, err error) {
2020-01-09 19:23:42 +00:00
sb.lk.Lock()
ss, ok := sb.sectors[sid]
sb.lk.Unlock()
if !ok {
return nil, xerrors.Errorf("no such sector %d", sid)
}
ss.lk.Lock()
defer ss.lk.Unlock()
if ss.failed {
return nil, xerrors.Errorf("[mock] cannot commit failed sector %d", sid)
}
if ss.state != statePreCommit {
return nil, xerrors.Errorf("cannot commit sector that has not been precommitted")
}
opFinishWait(ctx)
2020-01-09 19:23:42 +00:00
2020-01-13 20:47:27 +00:00
var out [32]byte
for i := range out {
2020-02-28 18:06:59 +00:00
out[i] = unsealed.Bytes()[i] + sealedCid.Bytes()[31-i] - ticket[i]*seed[i] ^ byte(sid&0xff)
2020-01-13 20:47:27 +00:00
}
2020-02-26 22:54:34 +00:00
2020-01-13 20:47:27 +00:00
return out[:], nil
}
2020-01-09 18:28:14 +00:00
func (sb *SBMock) SealCommit2(ctx context.Context, sectorNum abi.SectorNumber, phase1Out []byte) (proof []byte, err error) {
var out [32]byte
for i := range out {
2020-02-28 18:06:59 +00:00
out[i] = phase1Out[i] ^ byte(sectorNum&0xff)
}
2020-01-09 18:28:14 +00:00
return out[:], nil
2020-01-09 18:28:14 +00:00
}
2020-01-09 19:23:42 +00:00
// Test Instrumentation Methods
func (sb *SBMock) FailSector(sid abi.SectorNumber) error {
2020-01-09 19:23:42 +00:00
sb.lk.Lock()
defer sb.lk.Unlock()
ss, ok := sb.sectors[sid]
if !ok {
return fmt.Errorf("no such sector in sectorbuilder")
}
ss.failed = true
return nil
}
func opFinishWait(ctx context.Context) {
val, ok := ctx.Value("opfinish").(chan struct{})
if !ok {
return
}
<-val
2020-01-09 19:23:42 +00:00
}
func AddOpFinish(ctx context.Context) (context.Context, func()) {
done := make(chan struct{})
return context.WithValue(ctx, "opfinish", done), func() {
close(done)
}
}
2020-02-26 22:54:34 +00:00
func (sb *SBMock) ComputeElectionPoSt(sectorInfo []abi.SectorInfo, challengeSeed abi.PoStRandomness, winners []abi.PoStCandidate) ([]abi.PoStProof, error) {
2020-01-13 20:47:27 +00:00
panic("implement me")
}
2020-02-26 22:54:34 +00:00
func (sb *SBMock) GenerateEPostCandidates(sectorInfo []abi.SectorInfo, challengeSeed abi.PoStRandomness, faults []abi.SectorNumber) ([]ffi.PoStCandidateWithTicket, error) {
2020-01-13 20:47:27 +00:00
if len(faults) > 0 {
panic("todo")
}
2020-02-26 22:54:34 +00:00
n := sectorbuilder.ElectionPostChallengeCount(uint64(len(sectorInfo)), uint64(len(faults)))
if n > uint64(len(sectorInfo)) {
n = uint64(len(sectorInfo))
2020-01-13 20:47:27 +00:00
}
2020-02-26 22:54:34 +00:00
out := make([]ffi.PoStCandidateWithTicket, n)
2020-01-13 20:47:27 +00:00
seed := big.NewInt(0).SetBytes(challengeSeed[:])
2020-02-26 22:54:34 +00:00
start := seed.Mod(seed, big.NewInt(int64(len(sectorInfo)))).Int64()
2020-01-13 20:47:27 +00:00
2020-01-14 01:24:04 +00:00
for i := range out {
2020-02-26 22:54:34 +00:00
out[i] = ffi.PoStCandidateWithTicket{
Candidate: abi.PoStCandidate{
SectorID: abi.SectorID{
Number: abi.SectorNumber((int(start) + i) % len(sectorInfo)),
Miner: 1125125, //TODO
},
PartialTicket: abi.PartialTicket(challengeSeed),
},
2020-01-13 20:47:27 +00:00
}
}
return out, nil
}
2020-02-26 22:54:34 +00:00
func (sb *SBMock) ReadPieceFromSealedSector(ctx context.Context, sectorID abi.SectorNumber, offset sectorbuilder.UnpaddedByteIndex, size abi.UnpaddedPieceSize, ticket abi.SealRandomness, commD cid.Cid) (io.ReadCloser, error) {
2020-01-14 01:24:04 +00:00
if len(sb.sectors[sectorID].pieces) > 1 {
panic("implme")
}
2020-02-26 22:54:34 +00:00
return ioutil.NopCloser(io.LimitReader(bytes.NewReader(sb.sectors[sectorID].pieces[0].Bytes()[offset:]), int64(size))), nil
2020-01-13 20:47:27 +00:00
}
2020-02-26 22:54:34 +00:00
func (sb *SBMock) StageFakeData() (abi.SectorNumber, []abi.PieceInfo, error) {
2020-02-21 19:28:01 +00:00
usize := abi.PaddedPieceSize(sb.sectorSize).Unpadded()
2020-02-11 01:23:03 +00:00
sid, err := sb.AcquireSectorNumber()
if err != nil {
return 0, nil, err
}
buf := make([]byte, usize)
rand.Read(buf)
2020-01-31 01:18:48 +00:00
pi, err := sb.AddPiece(context.TODO(), usize, sid, bytes.NewReader(buf), nil)
if err != nil {
return 0, nil, err
}
2020-02-26 22:54:34 +00:00
return sid, []abi.PieceInfo{pi}, nil
2020-01-09 19:23:42 +00:00
}
2020-01-13 20:47:27 +00:00
func (sb *SBMock) FinalizeSector(context.Context, abi.SectorNumber) error {
2020-01-31 01:27:38 +00:00
return nil
2020-01-31 01:18:48 +00:00
}
2020-02-26 22:54:34 +00:00
func (m mockVerif) VerifyElectionPost(ctx context.Context, pvi abi.PoStVerifyInfo) (bool, error) {
2020-01-13 20:47:27 +00:00
panic("implement me")
}
2020-02-26 22:54:34 +00:00
func (m mockVerif) VerifyFallbackPost(ctx context.Context, pvi abi.PoStVerifyInfo) (bool, error) {
2020-01-13 20:47:27 +00:00
panic("implement me")
}
2020-02-26 22:54:34 +00:00
func (m mockVerif) VerifySeal(svi abi.SealVerifyInfo) (bool, error) {
if len(svi.OnChain.Proof) != 32 { // Real ones are longer, but this should be fine
2020-01-13 20:47:27 +00:00
return false, nil
}
2020-02-26 22:54:34 +00:00
for i, b := range svi.OnChain.Proof {
if b != svi.UnsealedCID.Bytes()[i]+svi.OnChain.SealedCID.Bytes()[31-i]-svi.InteractiveRandomness[i]*svi.Randomness[i] {
2020-01-13 20:47:27 +00:00
return false, nil
}
}
return true, nil
}
2020-02-26 22:54:34 +00:00
func (m mockVerif) GenerateDataCommitment(ssize abi.PaddedPieceSize, pieces []abi.PieceInfo) (cid.Cid, error) {
2020-01-13 20:47:27 +00:00
if len(pieces) != 1 {
panic("todo")
}
2020-02-26 22:54:34 +00:00
if pieces[0].Size != ssize {
2020-02-27 00:42:39 +00:00
fmt.Println("wrong sizes? ", pieces[0].Size, ssize)
2020-01-13 20:47:27 +00:00
panic("todo")
}
2020-02-26 22:54:34 +00:00
return pieces[0].PieceCID, nil
2020-01-13 20:47:27 +00:00
}
var MockVerifier = mockVerif{}
var _ sectorbuilder.Verifier = MockVerifier
var _ sectorbuilder.Basic = &SBMock{}