2019-12-06 14:06:42 +00:00
|
|
|
package actors_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
2020-01-07 18:23:49 +00:00
|
|
|
"math"
|
2019-12-06 14:06:42 +00:00
|
|
|
"math/rand"
|
|
|
|
"testing"
|
|
|
|
|
2019-12-19 20:13:17 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2020-01-07 16:18:35 +00:00
|
|
|
"github.com/filecoin-project/go-sectorbuilder"
|
2019-12-06 14:06:42 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2020-01-07 21:51:33 +00:00
|
|
|
"github.com/filecoin-project/lotus/build"
|
2019-12-06 14:06:42 +00:00
|
|
|
"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"
|
2020-01-07 18:23:49 +00:00
|
|
|
"github.com/filecoin-project/lotus/lib/rlepluslazy"
|
2019-12-06 14:06:42 +00:00
|
|
|
hamt "github.com/ipfs/go-hamt-ipld"
|
|
|
|
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
2020-01-07 18:23:49 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2019-12-06 14:06:42 +00:00
|
|
|
cbg "github.com/whyrusleeping/cbor-gen"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestMinerCommitSectors(t *testing.T) {
|
|
|
|
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",
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
h := NewHarness(t, opts...)
|
|
|
|
h.vm.Syscalls.ValidatePoRep = func(ctx context.Context, maddr address.Address, ssize uint64, commD, commR, ticket, proof, seed []byte, sectorID uint64) (bool, aerrors.ActorError) {
|
|
|
|
// all proofs are valid
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ret, _ := h.SendFunds(t, worker, minerAddr, types.NewInt(100000))
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
|
|
|
|
ret, _ = h.InvokeWithValue(t, client, actors.StorageMarketAddress, actors.SMAMethods.AddBalance, types.NewInt(2000), nil)
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
|
|
|
|
addSectorToMiner(h, t, minerAddr, worker, client, 1)
|
|
|
|
|
|
|
|
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
2020-01-07 18:23:49 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
type badRuns struct {
|
|
|
|
done bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *badRuns) HasNext() bool {
|
|
|
|
return !br.done
|
2019-12-06 14:06:42 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 18:23:49 +00:00
|
|
|
func (br *badRuns) NextRun() (rlepluslazy.Run, error) {
|
|
|
|
br.done = true
|
|
|
|
return rlepluslazy.Run{true, math.MaxInt64}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ rlepluslazy.RunIterator = (*badRuns)(nil)
|
|
|
|
|
2019-12-21 04:02:18 +00:00
|
|
|
func TestMinerSubmitBadFault(t *testing.T) {
|
2020-01-07 21:51:33 +00:00
|
|
|
oldSS, oldMin := build.SectorSizes, build.MinimumMinerPower
|
|
|
|
build.SectorSizes, build.MinimumMinerPower = []uint64{1024}, 1024
|
|
|
|
defer func() {
|
|
|
|
build.SectorSizes, build.MinimumMinerPower = oldSS, oldMin
|
|
|
|
}()
|
|
|
|
|
2019-12-21 04:02:18 +00:00
|
|
|
var worker, client address.Address
|
|
|
|
var minerAddr address.Address
|
|
|
|
opts := []HarnessOpt{
|
|
|
|
HarnessAddr(&worker, 1000000),
|
|
|
|
HarnessAddr(&client, 1000000),
|
2020-01-07 21:51:33 +00:00
|
|
|
HarnessAddMiner(&minerAddr, &worker),
|
2019-12-21 04:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
h := NewHarness(t, opts...)
|
|
|
|
h.vm.Syscalls.ValidatePoRep = func(ctx context.Context, maddr address.Address, ssize uint64, commD, commR, ticket, proof, seed []byte, sectorID uint64) (bool, aerrors.ActorError) {
|
|
|
|
// all proofs are valid
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ret, _ := h.SendFunds(t, worker, minerAddr, types.NewInt(100000))
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
|
|
|
|
ret, _ = h.InvokeWithValue(t, client, actors.StorageMarketAddress, actors.SMAMethods.AddBalance, types.NewInt(2000), nil)
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
|
|
|
|
addSectorToMiner(h, t, minerAddr, worker, client, 1)
|
|
|
|
|
|
|
|
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
|
|
|
|
|
|
|
bf := types.NewBitField()
|
|
|
|
bf.Set(6)
|
|
|
|
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})
|
|
|
|
|
2020-01-07 21:51:33 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-12-21 04:04:38 +00:00
|
|
|
badnum := uint64(0)
|
|
|
|
badnum--
|
|
|
|
bf = types.NewBitField()
|
|
|
|
bf.Set(badnum)
|
2020-01-07 18:23:49 +00:00
|
|
|
bf.Set(badnum - 1)
|
2019-12-21 04:04:38 +00:00
|
|
|
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)
|
2020-01-07 18:23:49 +00:00
|
|
|
|
2019-12-21 04:04:38 +00:00
|
|
|
ApplyOK(t, ret)
|
2020-01-07 18:23:49 +00:00
|
|
|
assertSectorIDs(h, t, minerAddr, []uint64{1})
|
|
|
|
|
2020-01-07 18:59:31 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-01-07 18:23:49 +00:00
|
|
|
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})
|
2019-12-21 04:04:38 +00:00
|
|
|
|
2019-12-21 04:02:18 +00:00
|
|
|
bf = types.NewBitField()
|
|
|
|
bf.Set(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{})
|
2019-12-21 04:04:38 +00:00
|
|
|
|
2019-12-21 04:02:18 +00:00
|
|
|
}
|
|
|
|
|
2019-12-06 14:06:42 +00:00
|
|
|
func addSectorToMiner(h *Harness, t *testing.T, minerAddr, worker, client address.Address, sid uint64) {
|
|
|
|
t.Helper()
|
|
|
|
s := sectorbuilder.UserBytesForSectorSize(1024)
|
|
|
|
deal := h.makeFakeDeal(t, minerAddr, worker, client, s)
|
|
|
|
ret, _ := h.Invoke(t, worker, actors.StorageMarketAddress, actors.SMAMethods.PublishStorageDeals,
|
|
|
|
&actors.PublishStorageDealsParams{
|
|
|
|
Deals: []actors.StorageDealProposal{*deal},
|
|
|
|
})
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
var dealIds actors.PublishStorageDealResponse
|
|
|
|
if err := dealIds.UnmarshalCBOR(bytes.NewReader(ret.Return)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
dealid := dealIds.DealIDs[0]
|
|
|
|
|
|
|
|
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.PreCommitSector,
|
|
|
|
&actors.SectorPreCommitInfo{
|
|
|
|
SectorNumber: sid,
|
|
|
|
CommR: []byte("cats"),
|
|
|
|
SealEpoch: 10,
|
|
|
|
DealIDs: []uint64{dealid},
|
|
|
|
})
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
|
|
|
|
h.BlockHeight += 100
|
|
|
|
ret, _ = h.Invoke(t, worker, minerAddr, actors.MAMethods.ProveCommitSector,
|
|
|
|
&actors.SectorProveCommitInfo{
|
|
|
|
Proof: []byte("prooofy"),
|
|
|
|
SectorID: sid,
|
|
|
|
DealIDs: []uint64{dealid}, // TODO: weird that i have to pass this again
|
|
|
|
})
|
|
|
|
ApplyOK(t, ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertSectorIDs(h *Harness, t *testing.T, maddr address.Address, ids []uint64) {
|
|
|
|
t.Helper()
|
|
|
|
sectors, err := getMinerSectorSet(context.TODO(), h.vm.StateTree(), h.bs, maddr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(sectors) != len(ids) {
|
|
|
|
t.Fatal("miner has wrong number of sectors in their sector set")
|
|
|
|
}
|
|
|
|
|
|
|
|
all := make(map[uint64]bool)
|
|
|
|
for _, s := range sectors {
|
|
|
|
all[s.SectorID] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, id := range ids {
|
|
|
|
if !all[id] {
|
|
|
|
t.Fatal("expected to find sector ID: ", id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 18:59:31 +00:00
|
|
|
func getMinerState(ctx context.Context, st types.StateTree, bs blockstore.Blockstore, maddr address.Address) (*actors.StorageMinerActorState, error) {
|
2019-12-06 14:06:42 +00:00
|
|
|
mact, err := st.GetActor(maddr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cst := hamt.CSTFromBstore(bs)
|
|
|
|
|
|
|
|
var mstate actors.StorageMinerActorState
|
|
|
|
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-07 18:59:31 +00:00
|
|
|
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
|
|
|
|
}
|
2019-12-06 14:06:42 +00:00
|
|
|
|
|
|
|
return stmgr.LoadSectorsFromSet(ctx, bs, mstate.Sectors)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Harness) makeFakeDeal(t *testing.T, miner, worker, client address.Address, size uint64) *actors.StorageDealProposal {
|
|
|
|
data := make([]byte, size)
|
|
|
|
rand.Read(data)
|
|
|
|
commP, err := sectorbuilder.GeneratePieceCommitment(bytes.NewReader(data), size)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
prop := actors.StorageDealProposal{
|
|
|
|
PieceRef: commP[:],
|
|
|
|
PieceSize: size,
|
|
|
|
//PieceSerialization SerializationMode // Needs to be here as it tells how data in the sector maps to PieceRef cid
|
|
|
|
|
|
|
|
Client: client,
|
|
|
|
Provider: miner,
|
|
|
|
|
|
|
|
ProposalExpiration: 10000,
|
|
|
|
Duration: 150,
|
|
|
|
|
|
|
|
StoragePricePerEpoch: types.NewInt(1),
|
|
|
|
StorageCollateral: types.NewInt(0),
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := api.SignWith(context.TODO(), h.w.Sign, client, &prop); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &prop
|
|
|
|
}
|