Merge pull request #1025 from filecoin-project/fix/faults-counting
Fix faults handling
This commit is contained in:
commit
d213bd1fee
@ -467,14 +467,21 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.AllMap()
|
||||
ss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if lerr != nil {
|
||||
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(err, 5, "RLE+ invalid")
|
||||
}
|
||||
|
||||
activeFaults := uint64(0)
|
||||
var sectorInfos []ffi.PublicSectorInfo
|
||||
if err := pss.ForEach(func(id uint64, v *cbg.Deferred) error {
|
||||
if faults[id] {
|
||||
activeFaults++
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -512,7 +519,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
}
|
||||
|
||||
if ok, lerr := sectorbuilder.VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
|
||||
sectorbuilder.NewSortedPublicSectorInfo(sectorInfos), seed[:], params.Proof, candidates, proverID, len(faults)); !ok || lerr != nil {
|
||||
sectorbuilder.NewSortedPublicSectorInfo(sectorInfos), seed[:], params.Proof, candidates, proverID, activeFaults); !ok || lerr != nil {
|
||||
if lerr != nil {
|
||||
// TODO: study PoST errors
|
||||
return nil, aerrors.Absorb(lerr, 4, "PoST error")
|
||||
@ -523,7 +530,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
}
|
||||
|
||||
// Post submission is successful!
|
||||
if err := onSuccessfulPoSt(self, vmctx); err != nil {
|
||||
if err := onSuccessfulPoSt(self, vmctx, activeFaults); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -834,6 +841,20 @@ func (sma StorageMinerActor) DeclareFaults(act *types.Actor, vmctx types.VMConte
|
||||
return nil, aerrors.Absorb(err, 1, "failed to merge bitfields")
|
||||
}
|
||||
|
||||
ss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.HandleExternalError(nerr, "failed to load sector set")
|
||||
}
|
||||
|
||||
cf, nerr := nfaults.Count()
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(nerr, 2, "could not decode RLE+")
|
||||
}
|
||||
|
||||
if cf > 2*ss.Count {
|
||||
return nil, aerrors.Newf(3, "too many declared faults: %d > %d", cf, 2*ss.Count)
|
||||
}
|
||||
|
||||
self.FaultSet = nfaults
|
||||
|
||||
self.LastFaultSubmission = vmctx.BlockHeight()
|
||||
@ -909,7 +930,41 @@ func (sma StorageMinerActor) SubmitElectionPoSt(act *types.Actor, vmctx types.VM
|
||||
return nil, aerrors.New(1, "slashed miners can't perform election PoSt")
|
||||
}
|
||||
|
||||
if err := onSuccessfulPoSt(self, vmctx); err != nil {
|
||||
pss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
|
||||
}
|
||||
|
||||
ss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
|
||||
}
|
||||
|
||||
activeFaults := uint64(0)
|
||||
for f := range faults {
|
||||
if f > amt.MaxIndex {
|
||||
continue
|
||||
}
|
||||
|
||||
var comms [][]byte
|
||||
err := pss.Get(f, &comms)
|
||||
if err != nil {
|
||||
var notfound *amt.ErrNotFound
|
||||
if !xerrors.As(err, ¬found) {
|
||||
return nil, aerrors.HandleExternalError(err, "failed to find sector in sector set")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
activeFaults++
|
||||
}
|
||||
|
||||
if err := onSuccessfulPoSt(self, vmctx, activeFaults); err != nil { // TODO
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -924,7 +979,7 @@ func (sma StorageMinerActor) SubmitElectionPoSt(act *types.Actor, vmctx types.VM
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func onSuccessfulPoSt(self *StorageMinerActorState, vmctx types.VMContext) aerrors.ActorError {
|
||||
func onSuccessfulPoSt(self *StorageMinerActorState, vmctx types.VMContext, activeFaults uint64) aerrors.ActorError {
|
||||
// TODO: some sector upkeep stuff that is very haphazard and unclear in the spec
|
||||
|
||||
var mi MinerInfo
|
||||
@ -937,7 +992,12 @@ func onSuccessfulPoSt(self *StorageMinerActorState, vmctx types.VMContext) aerro
|
||||
return aerrors.HandleExternalError(nerr, "failed to load proving set")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.All()
|
||||
ss, nerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if nerr != nil {
|
||||
return aerrors.HandleExternalError(nerr, "failed to load sector set")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.All(2 * ss.Count)
|
||||
if nerr != nil {
|
||||
return aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
|
||||
}
|
||||
@ -945,7 +1005,7 @@ func onSuccessfulPoSt(self *StorageMinerActorState, vmctx types.VMContext) aerro
|
||||
self.FaultSet = types.NewBitField()
|
||||
|
||||
oldPower := self.Power
|
||||
newPower := types.BigMul(types.NewInt(pss.Count-uint64(len(faults))), types.NewInt(mi.SectorSize))
|
||||
newPower := types.BigMul(types.NewInt(pss.Count-activeFaults), types.NewInt(mi.SectorSize))
|
||||
|
||||
// If below the minimum size requirement, miners have zero power
|
||||
if newPower.LessThan(types.NewInt(build.MinimumMinerPower)) {
|
||||
|
@ -3,18 +3,22 @@ package actors_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/rlepluslazy"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"github.com/stretchr/testify/assert"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
@ -50,23 +54,37 @@ func TestMinerCommitSectors(t *testing.T) {
|
||||
addSectorToMiner(h, t, minerAddr, worker, client, 1)
|
||||
|
||||
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
||||
|
||||
}
|
||||
|
||||
type badRuns struct {
|
||||
done bool
|
||||
}
|
||||
|
||||
func (br *badRuns) HasNext() bool {
|
||||
return !br.done
|
||||
}
|
||||
|
||||
func (br *badRuns) NextRun() (rlepluslazy.Run, error) {
|
||||
br.done = true
|
||||
return rlepluslazy.Run{true, math.MaxInt64}, nil
|
||||
}
|
||||
|
||||
var _ rlepluslazy.RunIterator = (*badRuns)(nil)
|
||||
|
||||
func TestMinerSubmitBadFault(t *testing.T) {
|
||||
oldSS, oldMin := build.SectorSizes, build.MinimumMinerPower
|
||||
build.SectorSizes, build.MinimumMinerPower = []uint64{1024}, 1024
|
||||
defer func() {
|
||||
build.SectorSizes, build.MinimumMinerPower = oldSS, oldMin
|
||||
}()
|
||||
|
||||
var worker, client address.Address
|
||||
var minerAddr address.Address
|
||||
opts := []HarnessOpt{
|
||||
HarnessAddr(&worker, 1000000),
|
||||
HarnessAddr(&client, 1000000),
|
||||
HarnessActor(&minerAddr, &worker, actors.StorageMinerCodeCid,
|
||||
func() cbg.CBORMarshaler {
|
||||
return &actors.StorageMinerConstructorParams{
|
||||
Owner: worker,
|
||||
Worker: worker,
|
||||
SectorSize: 1024,
|
||||
PeerID: "fakepeerid",
|
||||
}
|
||||
}),
|
||||
HarnessAddMiner(&minerAddr, &worker),
|
||||
}
|
||||
|
||||
h := NewHarness(t, opts...)
|
||||
@ -92,18 +110,52 @@ func TestMinerSubmitBadFault(t *testing.T) {
|
||||
|
||||
ret, _ = h.Invoke(t, actors.NetworkAddress, minerAddr, actors.MAMethods.SubmitElectionPoSt, nil)
|
||||
ApplyOK(t, ret)
|
||||
|
||||
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
||||
|
||||
st, err := getMinerState(context.TODO(), h.vm.StateTree(), h.bs, minerAddr)
|
||||
assert.NoError(t, err)
|
||||
expectedPower := st.Power
|
||||
if types.BigCmp(expectedPower, types.NewInt(1024)) != 0 {
|
||||
t.Errorf("Expected power of 1024, got %s", expectedPower)
|
||||
}
|
||||
|
||||
badnum := uint64(0)
|
||||
badnum--
|
||||
bf = types.NewBitField()
|
||||
bf.Set(badnum)
|
||||
bf.Set(badnum - 1)
|
||||
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.DeclareFaults, &actors.DeclareFaultsParams{bf})
|
||||
ApplyOK(t, ret)
|
||||
|
||||
ret, _ = h.Invoke(t, actors.NetworkAddress, minerAddr, actors.MAMethods.SubmitElectionPoSt, nil)
|
||||
|
||||
ApplyOK(t, ret)
|
||||
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
||||
|
||||
st, err = getMinerState(context.TODO(), h.vm.StateTree(), h.bs, minerAddr)
|
||||
assert.NoError(t, err)
|
||||
currentPower := st.Power
|
||||
if types.BigCmp(expectedPower, currentPower) != 0 {
|
||||
t.Errorf("power changed and shouldn't have: %s != %s", expectedPower, currentPower)
|
||||
}
|
||||
|
||||
bf.Set(badnum - 2)
|
||||
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.DeclareFaults, &actors.DeclareFaultsParams{bf})
|
||||
if ret.ExitCode != 3 {
|
||||
t.Errorf("expected exit code 3, got %d: %+v", ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
||||
|
||||
rle, err := rlepluslazy.EncodeRuns(&badRuns{}, []byte{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
bf, err = types.NewBitFieldFromBytes(rle)
|
||||
assert.NoError(t, err)
|
||||
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.DeclareFaults, &actors.DeclareFaultsParams{bf})
|
||||
if ret.ExitCode != 3 {
|
||||
t.Errorf("expected exit code 3, got %d: %+v", ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
||||
|
||||
bf = types.NewBitField()
|
||||
bf.Set(1)
|
||||
@ -175,7 +227,7 @@ func assertSectorIDs(h *Harness, t *testing.T, maddr address.Address, ids []uint
|
||||
}
|
||||
}
|
||||
|
||||
func getMinerSectorSet(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) ([]*api.ChainSectorInfo, error) {
|
||||
func getMinerState(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) (*actors.StorageMinerActorState, error) {
|
||||
mact, err := st.GetActor(maddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -187,6 +239,14 @@ func getMinerSectorSet(ctx context.Context, st types.StateTree, bs blockstore.Bl
|
||||
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mstate, nil
|
||||
}
|
||||
|
||||
func getMinerSectorSet(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) ([]*api.ChainSectorInfo, error) {
|
||||
mstate, err := getMinerState(ctx, st, bs, maddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stmgr.LoadSectorsFromSet(ctx, bs, mstate.Sectors)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ type CreateStorageMinerParams struct {
|
||||
|
||||
func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) ([]byte, ActorError) {
|
||||
if !build.SupportedSectorSize(params.SectorSize) {
|
||||
return nil, aerrors.New(1, "Unsupported sector size")
|
||||
return nil, aerrors.Newf(1, "Unsupported sector size: %d", params.SectorSize)
|
||||
}
|
||||
|
||||
var self StoragePowerState
|
||||
|
@ -115,6 +115,32 @@ func HarnessActor(actor *address.Address, creator *address.Address, code cid.Cid
|
||||
|
||||
}
|
||||
|
||||
func HarnessAddMiner(addr *address.Address, creator *address.Address) HarnessOpt {
|
||||
return func(t testing.TB, h *Harness) error {
|
||||
if h.Stage != HarnessPostInit {
|
||||
return nil
|
||||
}
|
||||
if !addr.Empty() {
|
||||
return xerrors.New("actor address should be empty")
|
||||
}
|
||||
ret, _ := h.InvokeWithValue(t, *creator, actors.StoragePowerAddress,
|
||||
actors.SPAMethods.CreateStorageMiner, types.NewInt(3000), &actors.StorageMinerConstructorParams{
|
||||
Owner: *creator,
|
||||
Worker: *creator,
|
||||
SectorSize: 1024,
|
||||
PeerID: "fakepeerid",
|
||||
})
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
return xerrors.Errorf("creating actor: %w", ret.ActorErr)
|
||||
}
|
||||
var err error
|
||||
*addr, err = address.NewFromBytes(ret.Return)
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func HarnessCtx(ctx context.Context) HarnessOpt {
|
||||
return func(t testing.TB, h *Harness) error {
|
||||
h.ctx = ctx
|
||||
@ -177,7 +203,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness {
|
||||
for _, opt := range options {
|
||||
err := opt(t, h)
|
||||
if err != nil {
|
||||
t.Fatalf("Applying options: %v", err)
|
||||
t.Fatalf("Applying options: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@ -9,6 +10,8 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var ErrBitFieldTooMany = errors.New("to many items in RLE")
|
||||
|
||||
type BitField struct {
|
||||
rle rlepluslazy.RLE
|
||||
|
||||
@ -16,14 +19,23 @@ type BitField struct {
|
||||
}
|
||||
|
||||
func NewBitField() BitField {
|
||||
rle, err := rlepluslazy.FromBuf([]byte{})
|
||||
bf, err := NewBitFieldFromBytes([]byte{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic(fmt.Sprintf("creating empty rle: %+v", err))
|
||||
}
|
||||
return BitField{
|
||||
rle: rle,
|
||||
bits: make(map[uint64]struct{}),
|
||||
return bf
|
||||
}
|
||||
|
||||
func NewBitFieldFromBytes(rle []byte) (BitField, error) {
|
||||
bf := BitField{}
|
||||
rlep, err := rlepluslazy.FromBuf(rle)
|
||||
if err != nil {
|
||||
return BitField{}, xerrors.Errorf("could not decode rle+: %w", err)
|
||||
}
|
||||
bf.rle = rlep
|
||||
bf.bits = make(map[uint64]struct{})
|
||||
return bf, nil
|
||||
|
||||
}
|
||||
|
||||
func BitFieldFromSet(setBits []uint64) BitField {
|
||||
@ -106,7 +118,14 @@ func (bf BitField) Count() (uint64, error) {
|
||||
}
|
||||
|
||||
// All returns all set bits
|
||||
func (bf BitField) All() ([]uint64, error) {
|
||||
func (bf BitField) All(max uint64) ([]uint64, error) {
|
||||
c, err := bf.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("count errror: %w", err)
|
||||
}
|
||||
if c > max {
|
||||
return nil, xerrors.Errorf("expected %d, got %d: %w", max, c, ErrBitFieldTooMany)
|
||||
}
|
||||
|
||||
runs, err := bf.sum()
|
||||
if err != nil {
|
||||
@ -121,7 +140,14 @@ func (bf BitField) All() ([]uint64, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (bf BitField) AllMap() (map[uint64]bool, error) {
|
||||
func (bf BitField) AllMap(max uint64) (map[uint64]bool, error) {
|
||||
c, err := bf.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("count errror: %w", err)
|
||||
}
|
||||
if c > max {
|
||||
return nil, xerrors.Errorf("expected %d, got %d: %w", max, c, ErrBitFieldTooMany)
|
||||
}
|
||||
|
||||
runs, err := bf.sum()
|
||||
if err != nil {
|
||||
|
@ -216,7 +216,7 @@ func IsTicketWinner(partialTicket []byte, ssizeI uint64, snum uint64, totpow Big
|
||||
return lhs.Cmp(rhs) < 0
|
||||
}
|
||||
|
||||
func ElectionPostChallengeCount(sectors uint64, faults int) uint64 {
|
||||
func ElectionPostChallengeCount(sectors uint64, faults uint64) uint64 {
|
||||
return sectorbuilder.ElectionPostChallengeCount(sectors, faults)
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -16,7 +16,7 @@ require (
|
||||
github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
||||
github.com/filecoin-project/go-paramfetch v0.0.0-20200102181131-b20d579f2878
|
||||
github.com/filecoin-project/go-sectorbuilder v0.0.0-20200107152336-0cbb2c483013
|
||||
github.com/filecoin-project/go-sectorbuilder v0.0.0-20200107220006-3361d30ea5ab
|
||||
github.com/filecoin-project/go-statestore v0.0.0-20200102200712-1f63c701c1e5
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -93,8 +93,8 @@ github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMX
|
||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ=
|
||||
github.com/filecoin-project/go-paramfetch v0.0.0-20200102181131-b20d579f2878 h1:YicJT9xhPzZ1SBGiJFNUCkfwqK/G9vFyY1ytKBSjNJA=
|
||||
github.com/filecoin-project/go-paramfetch v0.0.0-20200102181131-b20d579f2878/go.mod h1:40kI2Gv16mwcRsHptI3OAV4nlOEU7wVDc4RgMylNFjU=
|
||||
github.com/filecoin-project/go-sectorbuilder v0.0.0-20200107152336-0cbb2c483013 h1:OGpRq3HRxyrxZJtbNKCOsb5YTmc+RBLLwdAgwZfkRnY=
|
||||
github.com/filecoin-project/go-sectorbuilder v0.0.0-20200107152336-0cbb2c483013/go.mod h1:3OZ4E3B2OuwhJjtxR4r7hPU9bCfB+A+hm4alLEsaeDc=
|
||||
github.com/filecoin-project/go-sectorbuilder v0.0.0-20200107220006-3361d30ea5ab h1:bsrBNO1LwnhOLxPEXlSPal/WuY61mLJUCHYyD0NayHg=
|
||||
github.com/filecoin-project/go-sectorbuilder v0.0.0-20200107220006-3361d30ea5ab/go.mod h1:3OZ4E3B2OuwhJjtxR4r7hPU9bCfB+A+hm4alLEsaeDc=
|
||||
github.com/filecoin-project/go-statestore v0.0.0-20200102200712-1f63c701c1e5 h1:NZXq90YlfakSmB2/84dGr0AVmKYFA97+yyViBIgTFbk=
|
||||
github.com/filecoin-project/go-statestore v0.0.0-20200102200712-1f63c701c1e5/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
|
Loading…
Reference in New Issue
Block a user