diff --git a/api/api_storage.go b/api/api_storage.go index f8c000e7d..7b75fff60 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -24,6 +24,8 @@ type StorageMiner interface { ActorSectorSize(context.Context, address.Address) (abi.SectorSize, error) + MiningBase(context.Context) (*types.TipSet, error) + // Temp api for testing PledgeSector(context.Context) error diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index aff01078b..66baf0cdb 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -174,6 +174,8 @@ type StorageMinerStruct struct { ActorAddress func(context.Context) (address.Address, error) `perm:"read"` ActorSectorSize func(context.Context, address.Address) (abi.SectorSize, error) `perm:"read"` + MiningBase func(context.Context) (*types.TipSet, error) + MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"` MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"` @@ -652,6 +654,10 @@ func (c *StorageMinerStruct) ActorAddress(ctx context.Context) (address.Address, return c.Internal.ActorAddress(ctx) } +func (c *StorageMinerStruct) MiningBase(ctx context.Context) (*types.TipSet, error) { + return c.Internal.MiningBase(ctx) +} + func (c *StorageMinerStruct) ActorSectorSize(ctx context.Context, addr address.Address) (abi.SectorSize, error) { return c.Internal.ActorSectorSize(ctx, addr) } diff --git a/api/test/deals.go b/api/test/deals.go index e7f66ea0e..c10f9d6b0 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -9,6 +9,7 @@ import ( "math/rand" "os" "path/filepath" + "sync/atomic" "testing" "time" @@ -62,14 +63,14 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport fmt.Println("FILE CID: ", fcid) - mine := true + var mine int32 = 1 done := make(chan struct{}) go func() { defer close(done) - for mine { + for atomic.LoadInt32(&mine) == 1 { time.Sleep(blocktime) - if err := sn[0].MineOne(ctx); err != nil { + if err := sn[0].MineOne(ctx, func(bool) {}); err != nil { t.Error(err) } } @@ -86,7 +87,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport testRetrieval(t, err, client, ctx, fcid, carExport, data) - mine = false + atomic.StoreInt32(&mine, 0) fmt.Println("shutting down mining") <-done } diff --git a/api/test/mining.go b/api/test/mining.go index 94774048b..4ce7c9ec9 100644 --- a/api/test/mining.go +++ b/api/test/mining.go @@ -1,13 +1,25 @@ package test import ( + "bytes" "context" + "fmt" + "math/rand" + "os" + "sync/atomic" "testing" + "time" + + logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/node/impl" ) +var log = logging.Logger("apitest") + func (ts *testSuite) testMining(t *testing.T) { ctx := context.Background() apis, sn := ts.makeNodes(t, 1, oneMiner) @@ -21,7 +33,7 @@ func (ts *testSuite) testMining(t *testing.T) { require.NoError(t, err) <-newHeads - err = sn[0].MineOne(ctx) + err = sn[0].MineOne(ctx, func(bool) {}) require.NoError(t, err) <-newHeads @@ -30,3 +42,120 @@ func (ts *testSuite) testMining(t *testing.T) { require.NoError(t, err) require.Equal(t, abi.ChainEpoch(1), h2.Height()) } + +func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) { + os.Setenv("BELLMAN_NO_GPU", "1") + + // test making a deal with a fresh miner, and see if it starts to mine + + ctx := context.Background() + n, sn := b(t, 1, []StorageMiner{ + {Full: 0, Preseal: PresealGenesis}, + {Full: 0, Preseal: 0}, // TODO: Add support for storage miners on non-first full node + }) + client := n[0].FullNode.(*impl.FullNodeAPI) + provider := sn[1] + genesisMiner := sn[0] + + addrinfo, err := client.NetAddrsListen(ctx) + if err != nil { + t.Fatal(err) + } + + if err := provider.NetConnect(ctx, addrinfo); err != nil { + t.Fatal(err) + } + + if err := genesisMiner.NetConnect(ctx, addrinfo); err != nil { + t.Fatal(err) + } + + time.Sleep(time.Second) + + data := make([]byte, 600) + rand.New(rand.NewSource(5)).Read(data) + + r := bytes.NewReader(data) + fcid, err := client.ClientImportLocal(ctx, r) + if err != nil { + t.Fatal(err) + } + + fmt.Println("FILE CID: ", fcid) + + var mine int32 = 1 + done := make(chan struct{}) + minedTwo := make(chan struct{}) + + go func() { + defer close(done) + + prevExpect := 0 + for atomic.LoadInt32(&mine) != 0 { + wait := make(chan int, 2) + mdone := func(mined bool) { + go func() { + n := 0 + if mined { + n = 1 + } + wait <- n + }() + } + + if err := sn[0].MineOne(ctx, mdone); err != nil { + t.Error(err) + } + + if err := sn[1].MineOne(ctx, mdone); err != nil { + t.Error(err) + } + + expect := <-wait + expect += <-wait + + time.Sleep(blocktime) + + for { + n := 0 + for i, node := range sn { + mb, err := node.MiningBase(ctx) + if err != nil { + t.Error(err) + return + } + + if len(mb.Cids()) != expect { + log.Warnf("node %d mining base not complete (%d, want %d)", i, len(mb.Cids()), expect) + continue + } + n++ + } + if n == len(sn) { + break + } + time.Sleep(blocktime) + } + + if prevExpect == 2 && expect == 2 && minedTwo != nil { + close(minedTwo) + minedTwo = nil + } + + prevExpect = expect + } + }() + + deal := startDeal(t, provider, ctx, client, fcid) + + // TODO: this sleep is only necessary because deals don't immediately get logged in the dealstore, we should fix this + time.Sleep(time.Second) + + waitDealSealed(t, ctx, client, deal) + + <-minedTwo + + atomic.StoreInt32(&mine, 0) + fmt.Println("shutting down mining") + <-done +} diff --git a/api/test/test.go b/api/test/test.go index 675e50171..983624078 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -16,7 +16,7 @@ type TestNode struct { type TestStorageNode struct { api.StorageMiner - MineOne func(context.Context) error + MineOne func(context.Context, func(bool)) error } var PresealGenesis = -1 diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 705750d91..b480259d3 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -148,6 +148,10 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("getting proving set: %w", err) } + if len(sectorSet) == 0 { + return nil, nil + } + spt, err := ffiwrapper.SealProofTypeFromSectorSize(mas.Info.SectorSize) if err != nil { return nil, xerrors.Errorf("getting seal proof type: %w", err) @@ -449,6 +453,10 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, tsk types.TipSetKey return nil, xerrors.Errorf("getting wpost proving set: %w", err) } + if len(sectors) == 0 { + return nil, nil + } + mpow, tpow, err := GetPowerRaw(ctx, sm, lbst, maddr) if err != nil { return nil, xerrors.Errorf("failed to get power: %w", err) diff --git a/go.sum b/go.sum index 2cb366089..e7b244667 100644 --- a/go.sum +++ b/go.sum @@ -28,7 +28,9 @@ github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs= @@ -811,6 +813,7 @@ github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAri github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -1100,6 +1103,7 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/miner/miner.go b/miner/miner.go index 161fbddff..a9036f530 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -25,7 +25,8 @@ import ( var log = logging.Logger("miner") -type waitFunc func(ctx context.Context, baseTime uint64) error +// returns a callback reporting whether we mined a blocks in this round +type waitFunc func(ctx context.Context, baseTime uint64) (func(bool), error) func NewMiner(api api.FullNode, epp gen.WinningPoStProver, beacon beacon.RandomBeacon) *Miner { arc, err := lru.NewARC(10000) @@ -37,12 +38,12 @@ func NewMiner(api api.FullNode, epp gen.WinningPoStProver, beacon beacon.RandomB api: api, epp: epp, beacon: beacon, - waitFunc: func(ctx context.Context, baseTime uint64) error { + waitFunc: func(ctx context.Context, baseTime uint64) (func(bool), error) { // Wait around for half the block time in case other parents come in deadline := baseTime + build.PropagationDelay time.Sleep(time.Until(time.Unix(int64(deadline), 0))) - return nil + return func(bool) {}, nil }, minedBlockHeights: arc, } @@ -167,7 +168,8 @@ eventLoop: } // Wait until propagation delay period after block we plan to mine on - if err := m.waitFunc(ctx, prebase.ts.MinTimestamp()); err != nil { + onDone, err := m.waitFunc(ctx, prebase.TipSet.MinTimestamp()) + if err != nil { log.Error(err) return } @@ -177,8 +179,8 @@ eventLoop: log.Errorf("failed to get best mining candidate: %s", err) continue } - if base.ts.Equals(lastBase.ts) && lastBase.nullRounds == base.nullRounds { - log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.ts.Cids(), lastBase.nullRounds) + if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds { + log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds) time.Sleep(build.BlockDelay * time.Second) continue } @@ -197,6 +199,8 @@ eventLoop: } } + onDone(len(blks) != 0) + if len(blks) != 0 { btime := time.Unix(int64(blks[0].Header.Timestamp), 0) if time.Now().Before(btime) { @@ -232,7 +236,7 @@ eventLoop: } } } else { - nextRound := time.Unix(int64(base.ts.MinTimestamp()+uint64(build.BlockDelay*base.nullRounds)), 0) + nextRound := time.Unix(int64(base.TipSet.MinTimestamp()+uint64(build.BlockDelay*base.NullRounds)), 0) select { case <-time.After(time.Until(nextRound)): @@ -248,8 +252,8 @@ eventLoop: } type MiningBase struct { - ts *types.TipSet - nullRounds abi.ChainEpoch + TipSet *types.TipSet + NullRounds abi.ChainEpoch } func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) { @@ -259,7 +263,7 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) } if m.lastWork != nil { - if m.lastWork.ts.Equals(bts) { + if m.lastWork.TipSet.Equals(bts) { return m.lastWork, nil } @@ -267,7 +271,7 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) if err != nil { return nil, err } - ltsw, err := m.api.ChainTipSetWeight(ctx, m.lastWork.ts.Key()) + ltsw, err := m.api.ChainTipSetWeight(ctx, m.lastWork.TipSet.Key()) if err != nil { return nil, err } @@ -277,7 +281,7 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) } } - m.lastWork = &MiningBase{ts: bts} + m.lastWork = &MiningBase{TipSet: bts} return m.lastWork, nil } @@ -291,15 +295,19 @@ func (m *Miner) hasPower(ctx context.Context, addr address.Address, ts *types.Ti } func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningBase) (*types.BlockMsg, error) { - log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.ts.Cids())) + log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.TipSet.Cids())) start := time.Now() - round := base.ts.Height() + base.nullRounds + 1 + round := base.TipSet.Height() + base.NullRounds + 1 - mbi, err := m.api.MinerGetBaseInfo(ctx, addr, round, base.ts.Key()) + mbi, err := m.api.MinerGetBaseInfo(ctx, addr, round, base.TipSet.Key()) if err != nil { return nil, xerrors.Errorf("failed to get mining base info: %w", err) } + if mbi == nil { + base.NullRounds++ + return nil, nil + } beaconPrev := mbi.PrevBeaconEntry @@ -308,17 +316,17 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB return nil, xerrors.Errorf("get beacon entries failed: %w", err) } - hasPower, err := m.hasPower(ctx, addr, base.ts) + hasPower, err := m.hasPower(ctx, addr, base.TipSet) if err != nil { return nil, xerrors.Errorf("checking if miner is slashed: %w", err) } if !hasPower { // slashed or just have no power yet - base.nullRounds++ + base.NullRounds++ return nil, nil } - log.Infof("Time delta between now and our mining base: %ds (nulls: %d)", uint64(time.Now().Unix())-base.ts.MinTimestamp(), base.nullRounds) + log.Infof("Time delta between now and our mining base: %ds (nulls: %d)", uint64(time.Now().Unix())-base.TipSet.MinTimestamp(), base.NullRounds) rbase := beaconPrev if len(bvals) > 0 { @@ -330,18 +338,18 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB return nil, xerrors.Errorf("scratching ticket failed: %w", err) } - winner, err := gen.IsRoundWinner(ctx, base.ts, round, addr, rbase, mbi, m.api) + winner, err := gen.IsRoundWinner(ctx, base.TipSet, round, addr, rbase, mbi, m.api) if err != nil { return nil, xerrors.Errorf("failed to check if we win next round: %w", err) } if winner == nil { - base.nullRounds++ + base.NullRounds++ return nil, nil } // TODO: use the right dst, also NB: not using any 'entropy' in this call because nicola really didnt want it - rand, err := m.api.ChainGetRandomness(ctx, base.ts.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, base.ts.Height()+base.nullRounds, nil) + rand, err := m.api.ChainGetRandomness(ctx, base.TipSet.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, base.TipSet.Height()+base.NullRounds, nil) if err != nil { return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err) } @@ -354,7 +362,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB } // get pending messages early, - pending, err := m.api.MpoolPending(context.TODO(), base.ts.Key()) + pending, err := m.api.MpoolPending(context.TODO(), base.TipSet.Key()) if err != nil { return nil, xerrors.Errorf("failed to get pending messages: %w", err) } @@ -388,8 +396,8 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, brand * if err := addr.MarshalCBOR(buf); err != nil { return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) } - input, err := m.api.ChainGetRandomness(ctx, base.ts.Key(), crypto.DomainSeparationTag_TicketProduction, - base.ts.Height()+base.nullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) + input, err := m.api.ChainGetRandomness(ctx, base.TipSet.Key(), crypto.DomainSeparationTag_TicketProduction, + base.TipSet.Height()+base.NullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return nil, err } @@ -406,7 +414,7 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, brand * func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []abi.PoStProof, pending []*types.SignedMessage) (*types.BlockMsg, error) { - msgs, err := SelectMessages(context.TODO(), m.api.StateGetActor, base.ts, pending) + msgs, err := SelectMessages(context.TODO(), m.api.StateGetActor, base.TipSet, pending) if err != nil { return nil, xerrors.Errorf("message filtering failed: %w", err) } @@ -416,14 +424,14 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type msgs = msgs[:build.BlockMessageLimit] } - uts := base.ts.MinTimestamp() + uint64(build.BlockDelay*(base.nullRounds+1)) + uts := base.TipSet.MinTimestamp() + uint64(build.BlockDelay*(base.NullRounds+1)) - nheight := base.ts.Height() + base.nullRounds + 1 + nheight := base.TipSet.Height() + base.NullRounds + 1 // why even return this? that api call could just submit it for us return m.api.MinerCreateBlock(context.TODO(), &api.BlockTemplate{ Miner: addr, - Parents: base.ts.Key(), + Parents: base.TipSet.Key(), Ticket: ticket, Eproof: eproof, BeaconValues: bvals, diff --git a/miner/testminer.go b/miner/testminer.go index ea362793c..764bf7c89 100644 --- a/miner/testminer.go +++ b/miner/testminer.go @@ -10,7 +10,7 @@ import ( lru "github.com/hashicorp/golang-lru" ) -func NewTestMiner(nextCh <-chan struct{}, addr address.Address) func(api.FullNode, gen.WinningPoStProver, beacon.RandomBeacon) *Miner { +func NewTestMiner(nextCh <-chan func(bool), addr address.Address) func(api.FullNode, gen.WinningPoStProver, beacon.RandomBeacon) *Miner { return func(api api.FullNode, epp gen.WinningPoStProver, b beacon.RandomBeacon) *Miner { arc, err := lru.NewARC(10000) if err != nil { @@ -32,14 +32,13 @@ func NewTestMiner(nextCh <-chan struct{}, addr address.Address) func(api.FullNod } } -func chanWaiter(next <-chan struct{}) func(ctx context.Context, _ uint64) error { - return func(ctx context.Context, _ uint64) error { +func chanWaiter(next <-chan func(bool)) func(ctx context.Context, _ uint64) (func(bool), error) { + return func(ctx context.Context, _ uint64) (func(bool), error) { select { case <-ctx.Done(): - return ctx.Err() - case <-next: + return nil, ctx.Err() + case cb := <-next: + return cb, nil } - - return nil } } diff --git a/node/impl/storminer.go b/node/impl/storminer.go index db06bb6d1..3fe15d919 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -59,6 +59,14 @@ func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error return sm.Miner.Address(), nil } +func (sm *StorageMinerAPI) MiningBase(ctx context.Context) (*types.TipSet, error) { + mb, err := sm.BlockMiner.GetBestMiningCandidate(ctx) + if err != nil { + return nil, err + } + return mb.TipSet, nil +} + func (sm *StorageMinerAPI) ActorSectorSize(ctx context.Context, addr address.Address) (abi.SectorSize, error) { mi, err := sm.Full.StateMinerInfo(ctx, addr, types.EmptyTSK) if err != nil { diff --git a/node/mining_test.go b/node/mining_test.go deleted file mode 100644 index e949f813c..000000000 --- a/node/mining_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package node_test - -import ( - "testing" - "time" - - logging "github.com/ipfs/go-log/v2" - - "github.com/filecoin-project/lotus/api/test" -) - -func TestJoiningMiner(t *testing.T) { - logging.SetLogLevel("miner", "ERROR") - logging.SetLogLevel("chainstore", "ERROR") - logging.SetLogLevel("chain", "ERROR") - logging.SetLogLevel("sub", "ERROR") - logging.SetLogLevel("storageminer", "ERROR") - - test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, false) -} diff --git a/node/node_test.go b/node/node_test.go index d5fcc02f0..361597d4a 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -109,7 +109,7 @@ func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, a // start node var minerapi api.StorageMiner - mineBlock := make(chan struct{}) + mineBlock := make(chan func(bool)) // TODO: use stop _, err = node.New(ctx, node.StorageMiner(&minerapi), @@ -134,9 +134,9 @@ func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, a err = minerapi.NetConnect(ctx, remoteAddrs) require.NoError(t, err)*/ - mineOne := func(ctx context.Context) error { + mineOne := func(ctx context.Context, cb func(bool)) error { select { - case mineBlock <- struct{}{}: + case mineBlock <- cb: return nil case <-ctx.Done(): return ctx.Err() @@ -285,17 +285,8 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test fulls := make([]test.TestNode, nFull) storers := make([]test.TestStorageNode, len(storage)) - pk, _, err := crypto.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - - minerPid, err := peer.IDFromPrivateKey(pk) - require.NoError(t, err) - var genbuf bytes.Buffer - if len(storage) > 1 { - panic("need more peer IDs") - } // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE // TODO: would be great if there was a better way to fake the preseals @@ -304,6 +295,7 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test var maddrs []address.Address var presealDirs []string var keys []*wallet.Key + var pidKeys []crypto.PrivKey for i := 0; i < len(storage); i++ { maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i)) if err != nil { @@ -323,6 +315,13 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test if err != nil { t.Fatal(err) } + + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + minerPid, err := peer.IDFromPrivateKey(pk) + require.NoError(t, err) + genm.PeerId = minerPid wk, err := wallet.NewKey(*k) @@ -337,6 +336,7 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test }) keys = append(keys, wk) + pidKeys = append(pidKeys, pk) presealDirs = append(presealDirs, tdir) maddrs = append(maddrs, maddr) genms = append(genms, *genm) @@ -377,9 +377,6 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test for i, def := range storage { // TODO: support non-bootstrap miners - if i != 0 { - t.Fatal("only one storage node supported") - } if def.Full != 0 { t.Fatal("storage nodes only supported on the first full node") } @@ -392,10 +389,7 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test return nil, nil } - genMiner := maddrs[i] - wa := genms[i].Worker - - storers[i] = testStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options( + storers[i] = testStorageNode(ctx, t, genms[i].Worker, maddrs[i], pidKeys[i], f, mn, node.Options( node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { return mock.NewMockSectorMgr(5, build.SectorSizes[0]), nil }), @@ -479,3 +473,13 @@ func TestAPIDealFlowReal(t *testing.T) { test.TestDealFlow(t, builder, time.Second, false) } + +func TestDealMining(t *testing.T) { + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + test.TestDealMining(t, mockSbBuilder, 50*time.Millisecond, false) +}