testing: test 2-miner mining

This commit is contained in:
Łukasz Magiera 2020-04-23 23:12:42 +02:00
parent 40f56243d1
commit 86e7f5914b
12 changed files with 229 additions and 80 deletions

View File

@ -24,6 +24,8 @@ type StorageMiner interface {
ActorSectorSize(context.Context, address.Address) (abi.SectorSize, error) ActorSectorSize(context.Context, address.Address) (abi.SectorSize, error)
MiningBase(context.Context) (*types.TipSet, error)
// Temp api for testing // Temp api for testing
PledgeSector(context.Context) error PledgeSector(context.Context) error

View File

@ -174,6 +174,8 @@ type StorageMinerStruct struct {
ActorAddress func(context.Context) (address.Address, error) `perm:"read"` ActorAddress func(context.Context) (address.Address, error) `perm:"read"`
ActorSectorSize func(context.Context, address.Address) (abi.SectorSize, 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"` MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"`
MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, 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) 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) { func (c *StorageMinerStruct) ActorSectorSize(ctx context.Context, addr address.Address) (abi.SectorSize, error) {
return c.Internal.ActorSectorSize(ctx, addr) return c.Internal.ActorSectorSize(ctx, addr)
} }

View File

@ -9,6 +9,7 @@ import (
"math/rand" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
"sync/atomic"
"testing" "testing"
"time" "time"
@ -62,14 +63,14 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
fmt.Println("FILE CID: ", fcid) fmt.Println("FILE CID: ", fcid)
mine := true var mine int32 = 1
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
defer close(done) defer close(done)
for mine { for atomic.LoadInt32(&mine) == 1 {
time.Sleep(blocktime) time.Sleep(blocktime)
if err := sn[0].MineOne(ctx); err != nil { if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
t.Error(err) 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) testRetrieval(t, err, client, ctx, fcid, carExport, data)
mine = false atomic.StoreInt32(&mine, 0)
fmt.Println("shutting down mining") fmt.Println("shutting down mining")
<-done <-done
} }

View File

@ -1,13 +1,25 @@
package test package test
import ( import (
"bytes"
"context" "context"
"fmt"
"math/rand"
"os"
"sync/atomic"
"testing" "testing"
"time"
logging "github.com/ipfs/go-log/v2"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/filecoin-project/lotus/node/impl"
) )
var log = logging.Logger("apitest")
func (ts *testSuite) testMining(t *testing.T) { func (ts *testSuite) testMining(t *testing.T) {
ctx := context.Background() ctx := context.Background()
apis, sn := ts.makeNodes(t, 1, oneMiner) apis, sn := ts.makeNodes(t, 1, oneMiner)
@ -21,7 +33,7 @@ func (ts *testSuite) testMining(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
err = sn[0].MineOne(ctx) err = sn[0].MineOne(ctx, func(bool) {})
require.NoError(t, err) require.NoError(t, err)
<-newHeads <-newHeads
@ -30,3 +42,120 @@ func (ts *testSuite) testMining(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(1), h2.Height()) 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
}

View File

@ -16,7 +16,7 @@ type TestNode struct {
type TestStorageNode struct { type TestStorageNode struct {
api.StorageMiner api.StorageMiner
MineOne func(context.Context) error MineOne func(context.Context, func(bool)) error
} }
var PresealGenesis = -1 var PresealGenesis = -1

View File

@ -148,6 +148,10 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("getting proving set: %w", err) return nil, xerrors.Errorf("getting proving set: %w", err)
} }
if len(sectorSet) == 0 {
return nil, nil
}
spt, err := ffiwrapper.SealProofTypeFromSectorSize(mas.Info.SectorSize) spt, err := ffiwrapper.SealProofTypeFromSectorSize(mas.Info.SectorSize)
if err != nil { if err != nil {
return nil, xerrors.Errorf("getting seal proof type: %w", err) 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) 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) mpow, tpow, err := GetPowerRaw(ctx, sm, lbst, maddr)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get power: %w", err) return nil, xerrors.Errorf("failed to get power: %w", err)

4
go.sum
View File

@ -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/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 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= 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/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/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/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs= 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/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 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 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/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 v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= 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.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 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/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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -25,7 +25,8 @@ import (
var log = logging.Logger("miner") 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 { func NewMiner(api api.FullNode, epp gen.WinningPoStProver, beacon beacon.RandomBeacon) *Miner {
arc, err := lru.NewARC(10000) arc, err := lru.NewARC(10000)
@ -37,12 +38,12 @@ func NewMiner(api api.FullNode, epp gen.WinningPoStProver, beacon beacon.RandomB
api: api, api: api,
epp: epp, epp: epp,
beacon: beacon, 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 // Wait around for half the block time in case other parents come in
deadline := baseTime + build.PropagationDelay deadline := baseTime + build.PropagationDelay
time.Sleep(time.Until(time.Unix(int64(deadline), 0))) time.Sleep(time.Until(time.Unix(int64(deadline), 0)))
return nil return func(bool) {}, nil
}, },
minedBlockHeights: arc, minedBlockHeights: arc,
} }
@ -167,7 +168,8 @@ eventLoop:
} }
// Wait until propagation delay period after block we plan to mine on // 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) log.Error(err)
return return
} }
@ -177,8 +179,8 @@ eventLoop:
log.Errorf("failed to get best mining candidate: %s", err) log.Errorf("failed to get best mining candidate: %s", err)
continue continue
} }
if base.ts.Equals(lastBase.ts) && lastBase.nullRounds == base.nullRounds { if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds {
log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.ts.Cids(), lastBase.nullRounds) log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds)
time.Sleep(build.BlockDelay * time.Second) time.Sleep(build.BlockDelay * time.Second)
continue continue
} }
@ -197,6 +199,8 @@ eventLoop:
} }
} }
onDone(len(blks) != 0)
if len(blks) != 0 { if len(blks) != 0 {
btime := time.Unix(int64(blks[0].Header.Timestamp), 0) btime := time.Unix(int64(blks[0].Header.Timestamp), 0)
if time.Now().Before(btime) { if time.Now().Before(btime) {
@ -232,7 +236,7 @@ eventLoop:
} }
} }
} else { } 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 { select {
case <-time.After(time.Until(nextRound)): case <-time.After(time.Until(nextRound)):
@ -248,8 +252,8 @@ eventLoop:
} }
type MiningBase struct { type MiningBase struct {
ts *types.TipSet TipSet *types.TipSet
nullRounds abi.ChainEpoch NullRounds abi.ChainEpoch
} }
func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) { 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 != nil {
if m.lastWork.ts.Equals(bts) { if m.lastWork.TipSet.Equals(bts) {
return m.lastWork, nil return m.lastWork, nil
} }
@ -267,7 +271,7 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error)
if err != nil { if err != nil {
return nil, err 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 { if err != nil {
return nil, err 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 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) { 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() 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 { if err != nil {
return nil, xerrors.Errorf("failed to get mining base info: %w", err) return nil, xerrors.Errorf("failed to get mining base info: %w", err)
} }
if mbi == nil {
base.NullRounds++
return nil, nil
}
beaconPrev := mbi.PrevBeaconEntry 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) 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 { if err != nil {
return nil, xerrors.Errorf("checking if miner is slashed: %w", err) return nil, xerrors.Errorf("checking if miner is slashed: %w", err)
} }
if !hasPower { if !hasPower {
// slashed or just have no power yet // slashed or just have no power yet
base.nullRounds++ base.NullRounds++
return nil, nil 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 rbase := beaconPrev
if len(bvals) > 0 { 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) 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 { if err != nil {
return nil, xerrors.Errorf("failed to check if we win next round: %w", err) return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
} }
if winner == nil { if winner == nil {
base.nullRounds++ base.NullRounds++
return nil, nil return nil, nil
} }
// TODO: use the right dst, also NB: not using any 'entropy' in this call because nicola really didnt want it // 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 { if err != nil {
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err) 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, // 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 { if err != nil {
return nil, xerrors.Errorf("failed to get pending messages: %w", err) 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 { if err := addr.MarshalCBOR(buf); err != nil {
return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err)
} }
input, err := m.api.ChainGetRandomness(ctx, base.ts.Key(), crypto.DomainSeparationTag_TicketProduction, input, err := m.api.ChainGetRandomness(ctx, base.TipSet.Key(), crypto.DomainSeparationTag_TicketProduction,
base.ts.Height()+base.nullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) base.TipSet.Height()+base.NullRounds+1-build.TicketRandomnessLookback, buf.Bytes())
if err != nil { if err != nil {
return nil, err 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, 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) { 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 { if err != nil {
return nil, xerrors.Errorf("message filtering failed: %w", err) 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] 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 // why even return this? that api call could just submit it for us
return m.api.MinerCreateBlock(context.TODO(), &api.BlockTemplate{ return m.api.MinerCreateBlock(context.TODO(), &api.BlockTemplate{
Miner: addr, Miner: addr,
Parents: base.ts.Key(), Parents: base.TipSet.Key(),
Ticket: ticket, Ticket: ticket,
Eproof: eproof, Eproof: eproof,
BeaconValues: bvals, BeaconValues: bvals,

View File

@ -10,7 +10,7 @@ import (
lru "github.com/hashicorp/golang-lru" 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 { return func(api api.FullNode, epp gen.WinningPoStProver, b beacon.RandomBeacon) *Miner {
arc, err := lru.NewARC(10000) arc, err := lru.NewARC(10000)
if err != nil { 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 { func chanWaiter(next <-chan func(bool)) func(ctx context.Context, _ uint64) (func(bool), error) {
return func(ctx context.Context, _ uint64) error { return func(ctx context.Context, _ uint64) (func(bool), error) {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return ctx.Err() return nil, ctx.Err()
case <-next: case cb := <-next:
} return cb, nil
}
return nil
} }
} }

View File

@ -59,6 +59,14 @@ func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error
return sm.Miner.Address(), nil 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) { func (sm *StorageMinerAPI) ActorSectorSize(ctx context.Context, addr address.Address) (abi.SectorSize, error) {
mi, err := sm.Full.StateMinerInfo(ctx, addr, types.EmptyTSK) mi, err := sm.Full.StateMinerInfo(ctx, addr, types.EmptyTSK)
if err != nil { if err != nil {

View File

@ -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)
}

View File

@ -109,7 +109,7 @@ func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, a
// start node // start node
var minerapi api.StorageMiner var minerapi api.StorageMiner
mineBlock := make(chan struct{}) mineBlock := make(chan func(bool))
// TODO: use stop // TODO: use stop
_, err = node.New(ctx, _, err = node.New(ctx,
node.StorageMiner(&minerapi), node.StorageMiner(&minerapi),
@ -134,9 +134,9 @@ func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, a
err = minerapi.NetConnect(ctx, remoteAddrs) err = minerapi.NetConnect(ctx, remoteAddrs)
require.NoError(t, err)*/ require.NoError(t, err)*/
mineOne := func(ctx context.Context) error { mineOne := func(ctx context.Context, cb func(bool)) error {
select { select {
case mineBlock <- struct{}{}: case mineBlock <- cb:
return nil return nil
case <-ctx.Done(): case <-ctx.Done():
return ctx.Err() return ctx.Err()
@ -285,17 +285,8 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test
fulls := make([]test.TestNode, nFull) fulls := make([]test.TestNode, nFull)
storers := make([]test.TestStorageNode, len(storage)) 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 var genbuf bytes.Buffer
if len(storage) > 1 {
panic("need more peer IDs")
}
// PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE
// TODO: would be great if there was a better way to fake the preseals // 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 maddrs []address.Address
var presealDirs []string var presealDirs []string
var keys []*wallet.Key var keys []*wallet.Key
var pidKeys []crypto.PrivKey
for i := 0; i < len(storage); i++ { for i := 0; i < len(storage); i++ {
maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i)) maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i))
if err != nil { if err != nil {
@ -323,6 +315,13 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test
if err != nil { if err != nil {
t.Fatal(err) 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 genm.PeerId = minerPid
wk, err := wallet.NewKey(*k) wk, err := wallet.NewKey(*k)
@ -337,6 +336,7 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test
}) })
keys = append(keys, wk) keys = append(keys, wk)
pidKeys = append(pidKeys, pk)
presealDirs = append(presealDirs, tdir) presealDirs = append(presealDirs, tdir)
maddrs = append(maddrs, maddr) maddrs = append(maddrs, maddr)
genms = append(genms, *genm) genms = append(genms, *genm)
@ -377,9 +377,6 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test
for i, def := range storage { for i, def := range storage {
// TODO: support non-bootstrap miners // TODO: support non-bootstrap miners
if i != 0 {
t.Fatal("only one storage node supported")
}
if def.Full != 0 { if def.Full != 0 {
t.Fatal("storage nodes only supported on the first full node") 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 return nil, nil
} }
genMiner := maddrs[i] storers[i] = testStorageNode(ctx, t, genms[i].Worker, maddrs[i], pidKeys[i], f, mn, node.Options(
wa := genms[i].Worker
storers[i] = testStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options(
node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) {
return mock.NewMockSectorMgr(5, build.SectorSizes[0]), nil return mock.NewMockSectorMgr(5, build.SectorSizes[0]), nil
}), }),
@ -479,3 +473,13 @@ func TestAPIDealFlowReal(t *testing.T) {
test.TestDealFlow(t, builder, time.Second, false) 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)
}