From 9ad4a00cdacb83cba27ca1555da29a4778e46515 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 2 Dec 2019 22:41:28 -0800 Subject: [PATCH 01/12] fix miner message filter nonce checking --- api/api_full.go | 1 + api/struct.go | 5 +++++ miner/miner.go | 45 ++++++++++++++++++++++++++++++++--------- miner/miner_test.go | 4 ++-- node/impl/full/chain.go | 23 +++++++++++++++++++++ 5 files changed, 67 insertions(+), 11 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 2d5ed580c..726ae0175 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -29,6 +29,7 @@ type FullNode interface { ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error) ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error) ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error) + ChainGetTipSetMessages(context.Context, types.TipSetKey) ([]Message, error) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) ChainSetHead(context.Context, *types.TipSet) error diff --git a/api/struct.go b/api/struct.go index f47836f6a..3d797811b 100644 --- a/api/struct.go +++ b/api/struct.go @@ -45,6 +45,7 @@ type FullNodeStruct struct { ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"` ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"` + ChainGetTipSetMessages func(context.Context, types.TipSetKey) ([]Message, error) `perm:"read"` ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"` ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"` ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"` @@ -310,6 +311,10 @@ func (c *FullNodeStruct) ChainGetParentMessages(ctx context.Context, b cid.Cid) return c.Internal.ChainGetParentMessages(ctx, b) } +func (c *FullNodeStruct) ChainGetTipSetMessages(ctx context.Context, tsk types.TipSetKey) ([]Message, error) { + return c.Internal.ChainGetTipSetMessages(ctx, tsk) +} + func (c *FullNodeStruct) ChainNotify(ctx context.Context) (<-chan []*store.HeadChange, error) { return c.Internal.ChainNotify(ctx) } diff --git a/miner/miner.go b/miner/miner.go index 9bb166752..90d2c1c95 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -334,14 +334,40 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, base *M }, nil } -func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof) (*types.BlockMsg, error) { +func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types.TipSet) (uint64, *types.BigInt, error) { + // TODO: strong opportunities for some caching in this method + act, err := m.api.StateGetActor(ctx, addr, ts) + if err != nil { + return 0, nil, xerrors.Errorf("looking up actor failed: %w", err) + } + msgs, err := m.api.ChainGetTipSetMessages(ctx, ts.Key()) + if err != nil { + return 0, nil, xerrors.Errorf("failed to get tipset messages: %w", err) + } + + balance := act.Balance + curnonce := act.Nonce + for _, m := range msgs { + if m.Message.From == addr { + if m.Message.Nonce != curnonce { + return 0, nil, xerrors.Errorf("tipset messages had bad nonce: %s had nonce %d, expected %d", m.Cid, m.Message.Nonce, curnonce) + } + curnonce++ + balance = types.BigSub(balance, m.Message.RequiredFunds()) + } + } + + return curnonce, &balance, nil +} + +func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof) (*types.BlockMsg, error) { pending, err := m.api.MpoolPending(context.TODO(), base.ts) if err != nil { return nil, xerrors.Errorf("failed to get pending messages: %w", err) } - msgs, err := selectMessages(context.TODO(), m.api.StateGetActor, base, pending) + msgs, err := selectMessages(context.TODO(), m.actorLookup, base, pending) if err != nil { return nil, xerrors.Errorf("message filtering failed: %w", err) } @@ -354,7 +380,7 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type return m.api.MinerCreateBlock(context.TODO(), addr, base.ts, ticket, proof, msgs, nheight, uint64(uts)) } -type actorLookup func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) +type actorLookup func(context.Context, address.Address, *types.TipSet) (uint64, *types.BigInt, error) func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs []*types.SignedMessage) ([]*types.SignedMessage, error) { out := make([]*types.SignedMessage, 0, len(msgs)) @@ -367,14 +393,15 @@ func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs } from := msg.Message.From - act, err := al(ctx, from, base.ts) - if err != nil { - return nil, xerrors.Errorf("failed to check message sender balance: %w", err) - } if _, ok := inclNonces[from]; !ok { - inclNonces[from] = act.Nonce - inclBalances[from] = act.Balance + nonce, balance, err := al(ctx, from, base.ts) + if err != nil { + return nil, xerrors.Errorf("failed to check message sender balance: %w", err) + } + + inclNonces[from] = nonce + inclBalances[from] = *balance } if inclBalances[from].LessThan(msg.Message.RequiredFunds()) { diff --git a/miner/miner_test.go b/miner/miner_test.go index 160433d72..47e9e6d4a 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -33,8 +33,8 @@ func TestMessageFiltering(t *testing.T) { }, } - af := func(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, error) { - return actors[addr], nil + af := func(ctx context.Context, addr address.Address, ts *types.TipSet) (uint64, *types.BigInt, error) { + return actors[addr].Nonce, &actors[addr].Balance, nil } msgs := []types.Message{ diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 1e39be598..435e6b93e 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -68,6 +68,7 @@ func (a *ChainAPI) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api }, nil } +// TODO: Maybe deprecate in favor of just using ChainGetTipSetMessages? func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([]api.Message, error) { b, err := a.Chain.GetBlock(bcid) if err != nil { @@ -101,6 +102,28 @@ func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([] return out, nil } +func (a *ChainAPI) ChainGetTipSetMessages(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) { + ts, err := a.Chain.LoadTipSet(tsk.Cids()) + if err != nil { + return nil, xerrors.Errorf("failed to load tipset from key: %w", err) + } + + messages, err := a.Chain.MessagesForTipset(ts) + if err != nil { + return nil, xerrors.Errorf("getting messages for tipset: %w", err) + } + + var out []api.Message + for _, m := range messages { + out = append(out, api.Message{ + Cid: m.Cid(), + Message: m.VMMessage(), + }) + } + + return out, nil +} + func (a *ChainAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Cid) ([]*types.MessageReceipt, error) { b, err := a.Chain.GetBlock(bcid) if err != nil { From 5810922441d6e11c048cf10be29a187266545cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 17:39:47 +0100 Subject: [PATCH 02/12] This helps for some reason --- chain/stmgr/stmgr.go | 1 + miner/miner.go | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index c65dfe596..2fb73785a 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -195,6 +195,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl } if applied[m.From] != m.Nonce { + log.Infof("skipping message from %s: nonce check failed: exp %d, was %d", m.From, applied[m.From], m.Nonce) continue } applied[m.From]++ diff --git a/miner/miner.go b/miner/miner.go index 90d2c1c95..03f0f98c8 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -2,6 +2,7 @@ package miner import ( "context" + "sort" "sync" "time" @@ -348,16 +349,26 @@ func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types balance := act.Balance curnonce := act.Nonce + + sort.Slice(msgs, func(i, j int) bool { // TODO: is this actually needed? + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + + max := int64(-2) + for _, m := range msgs { if m.Message.From == addr { - if m.Message.Nonce != curnonce { - return 0, nil, xerrors.Errorf("tipset messages had bad nonce: %s had nonce %d, expected %d", m.Cid, m.Message.Nonce, curnonce) - } - curnonce++ + max = int64(m.Message.Nonce) balance = types.BigSub(balance, m.Message.RequiredFunds()) } } + max++ // next unapplied nonce + + if max != -1 && uint64(max) != curnonce { + return 0, nil, xerrors.Errorf("tipset messages from %s have too low nonce %d, expected %d, h: %d", addr, max, curnonce, ts.Height()) + } + return curnonce, &balance, nil } From f43ff07ab31ec058996e7adaa1d6f799c5b209ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 18:38:37 +0100 Subject: [PATCH 03/12] events: Allow revert on empty cache --- chain/events/tscache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/events/tscache.go b/chain/events/tscache.go index 1bccb4d65..cf1b8e580 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -62,7 +62,7 @@ func (tsc *tipSetCache) add(ts *types.TipSet) error { func (tsc *tipSetCache) revert(ts *types.TipSet) error { if tsc.len == 0 { - return xerrors.New("tipSetCache.revert: nothing to revert; cache is empty") + return nil // this can happen, and it's fine } if !tsc.cache[tsc.start].Equals(ts) { From 6127d82c7bc424c3459e7423a5bc0f48ea815552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 18:41:31 +0100 Subject: [PATCH 04/12] events: allow get on empty ts cache --- chain/events/tscache.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chain/events/tscache.go b/chain/events/tscache.go index cf1b8e580..2e58a3f5b 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -92,7 +92,8 @@ func (tsc *tipSetCache) getNonNull(height uint64) (*types.TipSet, error) { func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) { if tsc.len == 0 { - return nil, xerrors.New("tipSetCache.get: cache is empty") + log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height) + return tsc.storage(context.TODO(), height, nil) } headH := tsc.cache[tsc.start].Height() From 9c6e9212a242692605f5c70397dc5e0f5faa01f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 19:25:56 +0100 Subject: [PATCH 05/12] mining: get pending messages early --- chain/gen/gen.go | 34 +++++++++++++++++++++++++++------- miner/miner.go | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index c35ca5ce9..a823c1250 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -261,13 +261,17 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add VRFProof: vrfout, } - win, eproof, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], &mca{w: cg.w, sm: cg.sm}) + win, eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], &mca{w: cg.w, sm: cg.sm}) if err != nil { return nil, nil, xerrors.Errorf("checking round winner failed: %w", err) } if !win { return nil, tick, nil } + eproof, err := ComputeProof(ctx, cg.eppProvs[m], eproofin) + if err != nil { + return nil, nil, xerrors.Errorf("computing proof: %w", err) + } return eproof, tick, nil } @@ -466,7 +470,14 @@ func (epp *eppProvider) ComputeProof(ctx context.Context, _ sectorbuilder.Sorted return []byte("valid proof"), nil } -func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (bool, *types.EPostProof, error) { +type ProofInput struct { + sectors sectorbuilder.SortedPublicSectorInfo + hvrf []byte + winners []sectorbuilder.EPostCandidate + vrfout []byte +} + +func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (bool, *ProofInput, error) { r, err := a.ChainGetRandomness(ctx, ts.Key(), round-build.EcRandomnessLookback) if err != nil { return false, nil, xerrors.Errorf("chain get randomness: %w", err) @@ -529,16 +540,25 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add return false, nil, nil } - proof, err := epp.ComputeProof(ctx, sectors, hvrf[:], winners) + return true, &ProofInput{ + sectors: sectors, + hvrf: hvrf[:], + winners: winners, + vrfout: vrfout, + }, nil +} + +func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (*types.EPostProof, error) { + proof, err := epp.ComputeProof(ctx, pi.sectors, pi.hvrf, pi.winners) if err != nil { - return false, nil, xerrors.Errorf("failed to compute snark for election proof: %w", err) + return nil, xerrors.Errorf("failed to compute snark for election proof: %w", err) } ept := types.EPostProof{ Proof: proof, - PostRand: vrfout, + PostRand: pi.vrfout, } - for _, win := range winners { + for _, win := range pi.winners { ept.Candidates = append(ept.Candidates, types.EPostTicket{ Partial: win.PartialTicket[:], SectorID: win.SectorID, @@ -546,7 +566,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add }) } - return true, &ept, nil + return &ept, nil } type SignFunc func(context.Context, address.Address, []byte) (*types.Signature, error) diff --git a/miner/miner.go b/miner/miner.go index 03f0f98c8..461cf7c86 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -265,7 +265,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB return nil, xerrors.Errorf("scratching ticket failed: %w", err) } - win, proof, err := gen.IsRoundWinner(ctx, base.ts, int64(base.ts.Height()+base.nullRounds+1), addr, m.epp, m.api) + win, proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(base.ts.Height()+base.nullRounds+1), addr, m.epp, m.api) if err != nil { return nil, xerrors.Errorf("failed to check if we win next round: %w", err) } @@ -275,7 +275,18 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB return nil, nil } - b, err := m.createBlock(base, addr, ticket, proof) + // get pending messages early, + pending, err := m.api.MpoolPending(context.TODO(), base.ts) + if err != nil { + return nil, xerrors.Errorf("failed to get pending messages: %w", err) + } + + proof, err := gen.ComputeProof(ctx, m.epp, proofin) + if err != nil { + return nil, xerrors.Errorf("computing election proof: %w", err) + } + + b, err := m.createBlock(base, addr, ticket, proof, pending) if err != nil { return nil, xerrors.Errorf("failed to create block: %w", err) } @@ -372,12 +383,7 @@ func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types return curnonce, &balance, nil } -func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof) (*types.BlockMsg, error) { - pending, err := m.api.MpoolPending(context.TODO(), base.ts) - if err != nil { - return nil, xerrors.Errorf("failed to get pending messages: %w", err) - } - +func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof, pending []*types.SignedMessage) (*types.BlockMsg, error) { msgs, err := selectMessages(context.TODO(), m.actorLookup, base, pending) if err != nil { return nil, xerrors.Errorf("message filtering failed: %w", err) @@ -393,10 +399,24 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type type actorLookup func(context.Context, address.Address, *types.TipSet) (uint64, *types.BigInt, error) +func countFrom(msgs []*types.SignedMessage, from address.Address) (out int) { + for _, msg := range msgs { + if msg.Message.From == from { + out++ + } + } + return out +} + func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs []*types.SignedMessage) ([]*types.SignedMessage, error) { out := make([]*types.SignedMessage, 0, len(msgs)) inclNonces := make(map[address.Address]uint64) inclBalances := make(map[address.Address]types.BigInt) + + sort.Slice(msgs, func(i, j int) bool { // TODO: is this actually needed? + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + for _, msg := range msgs { if msg.Message.To == address.Undef { log.Warnf("message in mempool had bad 'To' address") @@ -421,12 +441,12 @@ func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs } if msg.Message.Nonce > inclNonces[from] { - log.Warnf("message in mempool has too high of a nonce (%d > %d) %s", msg.Message.Nonce, inclNonces[from], msg.Cid()) + log.Warnf("message in mempool has too high of a nonce (%d > %d) %s (%d pending for orig)", msg.Message.Nonce, inclNonces[from], msg.Cid(), countFrom(msgs, from)) continue } if msg.Message.Nonce < inclNonces[from] { - log.Warnf("message in mempool has already used nonce (%d < %d), from %s, to %s, %s", msg.Message.Nonce, inclNonces[from], msg.Message.From, msg.Message.To, msg.Cid()) + log.Warnf("message in mempool has already used nonce (%d < %d), from %s, to %s, %s (%d pending for)", msg.Message.Nonce, inclNonces[from], msg.Message.From, msg.Message.To, msg.Cid(), countFrom(msgs, from)) continue } From 96c04fc0a60be9f0072dfe27902cc02bf8d5a256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 20:33:29 +0100 Subject: [PATCH 06/12] mpool: Make MpoolPending more atomic --- chain/gen/gen.go | 4 +- chain/messagepool/messagepool.go | 111 ++++++++++++++++++------------- node/impl/full/mpool.go | 58 +++++++++++++++- 3 files changed, 122 insertions(+), 51 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index a823c1250..db97dae32 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -472,9 +472,9 @@ func (epp *eppProvider) ComputeProof(ctx context.Context, _ sectorbuilder.Sorted type ProofInput struct { sectors sectorbuilder.SortedPublicSectorInfo - hvrf []byte + hvrf []byte winners []sectorbuilder.EPostCandidate - vrfout []byte + vrfout []byte } func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (bool, *ProofInput, error) { diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 38b7e1fc4..38456a143 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -62,7 +62,7 @@ type MessagePool struct { pending map[address.Address]*msgSet pendingCount int - curTsLk sync.Mutex + curTsLk sync.Mutex // DO NOT LOCK INSIDE lk curTs *types.TipSet api Provider @@ -106,7 +106,7 @@ func (ms *msgSet) add(m *types.SignedMessage) error { } type Provider interface { - SubscribeHeadChanges(func(rev, app []*types.TipSet) error) + SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet PutMessage(m store.ChainMsg) (cid.Cid, error) PubSubPublish(string, []byte) error StateGetActor(address.Address, *types.TipSet) (*types.Actor, error) @@ -124,8 +124,9 @@ func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider { return &mpoolProvider{sm, ps} } -func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) { +func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { mpp.sm.ChainStore().SubscribeHeadChanges(cb) + return mpp.sm.ChainStore().GetHeaviestTipSet() } func (mpp *mpoolProvider) PutMessage(m store.ChainMsg) (cid.Cid, error) { @@ -173,7 +174,7 @@ func New(api Provider, ds dtypes.MetadataDS) (*MessagePool, error) { go mp.repubLocal() - api.SubscribeHeadChanges(func(rev, app []*types.TipSet) error { + mp.curTs = api.SubscribeHeadChanges(func(rev, app []*types.TipSet) error { err := mp.HeadChange(rev, app) if err != nil { log.Errorf("mpool head notif handler error: %+v", err) @@ -257,6 +258,12 @@ func (mp *MessagePool) Push(m *types.SignedMessage) error { } func (mp *MessagePool) Add(m *types.SignedMessage) error { + mp.curTsLk.Lock() + defer mp.curTsLk.Unlock() + return mp.addTs(m, mp.curTs) +} + +func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error { // big messages are bad, anti DOS if m.Size() > 32*1024 { return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig) @@ -275,7 +282,7 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error { return err } - snonce, err := mp.getStateNonce(m.Message.From) + snonce, err := mp.getStateNonce(m.Message.From, curTs) if err != nil { return xerrors.Errorf("failed to look up actor state nonce: %w", err) } @@ -333,14 +340,17 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage) error { } func (mp *MessagePool) GetNonce(addr address.Address) (uint64, error) { + mp.curTsLk.Lock() + defer mp.curTsLk.Lock() + mp.lk.Lock() defer mp.lk.Unlock() - return mp.getNonceLocked(addr) + return mp.getNonceLocked(addr, mp.curTs) } -func (mp *MessagePool) getNonceLocked(addr address.Address) (uint64, error) { - stateNonce, err := mp.getStateNonce(addr) // sanity check +func (mp *MessagePool) getNonceLocked(addr address.Address, curTs *types.TipSet) (uint64, error) { + stateNonce, err := mp.getStateNonce(addr, curTs) // sanity check if err != nil { return 0, err } @@ -359,22 +369,9 @@ func (mp *MessagePool) getNonceLocked(addr address.Address) (uint64, error) { return stateNonce, nil } -func (mp *MessagePool) setCurTipset(ts *types.TipSet) { - mp.curTsLk.Lock() - defer mp.curTsLk.Unlock() - mp.curTs = ts -} - -func (mp *MessagePool) getCurTipset() *types.TipSet { - mp.curTsLk.Lock() - defer mp.curTsLk.Unlock() - return mp.curTs -} - -func (mp *MessagePool) getStateNonce(addr address.Address) (uint64, error) { +func (mp *MessagePool) getStateNonce(addr address.Address, curTs *types.TipSet) (uint64, error) { // TODO: this method probably should be cached - curTs := mp.getCurTipset() act, err := mp.api.StateGetActor(addr, curTs) if err != nil { return 0, err @@ -417,13 +414,16 @@ func (mp *MessagePool) getStateBalance(addr address.Address) (types.BigInt, erro } func (mp *MessagePool) PushWithNonce(addr address.Address, cb func(uint64) (*types.SignedMessage, error)) (*types.SignedMessage, error) { + mp.curTsLk.Lock() + defer mp.curTsLk.Lock() + mp.lk.Lock() defer mp.lk.Unlock() if addr.Protocol() == address.ID { log.Warnf("Called pushWithNonce with ID address (%s) this might not be handled properly yet", addr) } - nonce, err := mp.getNonceLocked(addr) + nonce, err := mp.getNonceLocked(addr, mp.curTs) if err != nil { return nil, err } @@ -485,15 +485,19 @@ func (mp *MessagePool) Remove(from address.Address, nonce uint64) { } } -func (mp *MessagePool) Pending() []*types.SignedMessage { +func (mp *MessagePool) Pending() ([]*types.SignedMessage, *types.TipSet) { + mp.curTsLk.Lock() + defer mp.curTsLk.Unlock() + mp.lk.Lock() defer mp.lk.Unlock() + out := make([]*types.SignedMessage, 0) for a := range mp.pending { out = append(out, mp.pendingFor(a)...) } - return out + return out, mp.curTs } func (mp *MessagePool) pendingFor(a address.Address) []*types.SignedMessage { @@ -516,6 +520,8 @@ func (mp *MessagePool) pendingFor(a address.Address) []*types.SignedMessage { } func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) error { + mp.curTsLk.Lock() + defer mp.curTsLk.Unlock() for _, ts := range revert { pts, err := mp.api.LoadTipSet(ts.Parents()) @@ -523,27 +529,14 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) return err } - mp.setCurTipset(pts) - for _, b := range ts.Blocks() { - bmsgs, smsgs, err := mp.api.MessagesForBlock(b) - if err != nil { - return xerrors.Errorf("failed to get messages for revert block %s(height %d): %w", b.Cid(), b.Height, err) - } - for _, msg := range smsgs { - if err := mp.Add(msg); err != nil { - log.Error(err) // TODO: probably lots of spam in multi-block tsets - } - } + msgs, err := mp.MessagesForBlocks(ts.Blocks()) + if err != nil { + return err + } - for _, msg := range bmsgs { - smsg := mp.RecoverSig(msg) - if smsg != nil { - if err := mp.Add(smsg); err != nil { - log.Error(err) // TODO: probably lots of spam in multi-block tsets - } - } else { - log.Warnf("could not recover signature for bls message %s during a reorg revert", msg.Cid()) - } + for _, msg := range msgs { + if err := mp.addTs(msg, pts); err != nil { + log.Error(err) // TODO: probably lots of spam in multi-block tsets } } } @@ -562,12 +555,38 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) mp.Remove(msg.From, msg.Nonce) } } - mp.setCurTipset(ts) + + mp.curTs = ts } return nil } +func (mp *MessagePool) MessagesForBlocks(blks []*types.BlockHeader) ([]*types.SignedMessage, error) { + out := make([]*types.SignedMessage, 0) + + for _, b := range blks { + bmsgs, smsgs, err := mp.api.MessagesForBlock(b) + if err != nil { + return nil, xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err) + } + for _, msg := range smsgs { + out = append(out, msg) + } + + for _, msg := range bmsgs { + smsg := mp.RecoverSig(msg) + if smsg != nil { + out = append(out, smsg) + } else { + log.Warnf("could not recover signature for bls message %s", msg.Cid()) + } + } + } + + return out, nil +} + func (mp *MessagePool) RecoverSig(msg *types.Message) *types.SignedMessage { val, ok := mp.blsSigCache.Get(msg.Cid()) if !ok { diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 9ea34a7d1..249c62948 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -3,12 +3,14 @@ package full import ( "context" + "github.com/ipfs/go-cid" "go.uber.org/fx" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" ) @@ -17,13 +19,63 @@ type MpoolAPI struct { WalletAPI + Chain *store.ChainStore + Mpool *messagepool.MessagePool } func (a *MpoolAPI) MpoolPending(ctx context.Context, ts *types.TipSet) ([]*types.SignedMessage, error) { - // TODO: need to make sure we don't return messages that were already included in the referenced chain - // also need to accept ts == nil just fine, assume nil == chain.Head() - return a.Mpool.Pending(), nil + pending, mpts := a.Mpool.Pending() + + haveCids := map[cid.Cid]struct{}{} + for _, m := range pending { + haveCids[m.Cid()] = struct{}{} + } + + if mpts.Height() > ts.Height() { + return pending, nil + } + + for { + if mpts.Height() == ts.Height() { + if mpts.Equals(ts) { + return pending, nil + } + // different blocks in tipsets + + have, err := a.Mpool.MessagesForBlocks(ts.Blocks()) + if err != nil { + return nil, xerrors.Errorf("getting messages for base ts: %w", err) + } + + for _, m := range have { + haveCids[m.Cid()] = struct{}{} + } + } + + msgs, err := a.Mpool.MessagesForBlocks(ts.Blocks()) + if err != nil { + return nil, xerrors.Errorf(": %w", err) + } + + for _, m := range msgs { + if _, ok := haveCids[m.Cid()]; ok { + continue + } + + haveCids[m.Cid()] = struct{}{} + pending = append(pending, m) + } + + if mpts.Height() >= ts.Height() { + return pending, nil + } + + ts, err = a.Chain.LoadTipSet(ts.Parents()) + if err != nil { + return nil, xerrors.Errorf("loading parent tipset: %w", err) + } + } } func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) error { From 2d28bcf0579429109992db8173763eba64a07b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 20:34:31 +0100 Subject: [PATCH 07/12] Allow calling MpoolPending with nil TS --- node/impl/full/mpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 249c62948..7d2dd5639 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -32,7 +32,7 @@ func (a *MpoolAPI) MpoolPending(ctx context.Context, ts *types.TipSet) ([]*types haveCids[m.Cid()] = struct{}{} } - if mpts.Height() > ts.Height() { + if ts == nil || mpts.Height() > ts.Height() { return pending, nil } From 0e4c59d6a738b5ee7533ac4be6d6a03d62cca8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 20:47:17 +0100 Subject: [PATCH 08/12] miner: Don't deduce balance twice per msg in actorLookup --- miner/miner.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 461cf7c86..6004e343b 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -358,7 +358,6 @@ func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types return 0, nil, xerrors.Errorf("failed to get tipset messages: %w", err) } - balance := act.Balance curnonce := act.Nonce sort.Slice(msgs, func(i, j int) bool { // TODO: is this actually needed? @@ -370,7 +369,6 @@ func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types for _, m := range msgs { if m.Message.From == addr { max = int64(m.Message.Nonce) - balance = types.BigSub(balance, m.Message.RequiredFunds()) } } @@ -380,7 +378,7 @@ func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types return 0, nil, xerrors.Errorf("tipset messages from %s have too low nonce %d, expected %d, h: %d", addr, max, curnonce, ts.Height()) } - return curnonce, &balance, nil + return curnonce, &act.Balance, nil } func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof, pending []*types.SignedMessage) (*types.BlockMsg, error) { From d0448287a9baa39893ed9f17a083ea55031c18b0 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 3 Dec 2019 12:05:54 -0800 Subject: [PATCH 09/12] remove unnecessary code --- api/api_full.go | 1 - api/struct.go | 5 ----- miner/miner.go | 45 +++++------------------------------------ miner/miner_test.go | 4 ++-- node/impl/full/chain.go | 23 --------------------- 5 files changed, 7 insertions(+), 71 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 726ae0175..2d5ed580c 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -29,7 +29,6 @@ type FullNode interface { ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error) ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error) ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error) - ChainGetTipSetMessages(context.Context, types.TipSetKey) ([]Message, error) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) ChainReadObj(context.Context, cid.Cid) ([]byte, error) ChainSetHead(context.Context, *types.TipSet) error diff --git a/api/struct.go b/api/struct.go index 3d797811b..f47836f6a 100644 --- a/api/struct.go +++ b/api/struct.go @@ -45,7 +45,6 @@ type FullNodeStruct struct { ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"` ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"` - ChainGetTipSetMessages func(context.Context, types.TipSetKey) ([]Message, error) `perm:"read"` ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"` ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"` ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"` @@ -311,10 +310,6 @@ func (c *FullNodeStruct) ChainGetParentMessages(ctx context.Context, b cid.Cid) return c.Internal.ChainGetParentMessages(ctx, b) } -func (c *FullNodeStruct) ChainGetTipSetMessages(ctx context.Context, tsk types.TipSetKey) ([]Message, error) { - return c.Internal.ChainGetTipSetMessages(ctx, tsk) -} - func (c *FullNodeStruct) ChainNotify(ctx context.Context) (<-chan []*store.HeadChange, error) { return c.Internal.ChainNotify(ctx) } diff --git a/miner/miner.go b/miner/miner.go index 6004e343b..a5dc405c3 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -346,43 +346,8 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, base *M }, nil } -func (m *Miner) actorLookup(ctx context.Context, addr address.Address, ts *types.TipSet) (uint64, *types.BigInt, error) { - // TODO: strong opportunities for some caching in this method - act, err := m.api.StateGetActor(ctx, addr, ts) - if err != nil { - return 0, nil, xerrors.Errorf("looking up actor failed: %w", err) - } - - msgs, err := m.api.ChainGetTipSetMessages(ctx, ts.Key()) - if err != nil { - return 0, nil, xerrors.Errorf("failed to get tipset messages: %w", err) - } - - curnonce := act.Nonce - - sort.Slice(msgs, func(i, j int) bool { // TODO: is this actually needed? - return msgs[i].Message.Nonce < msgs[j].Message.Nonce - }) - - max := int64(-2) - - for _, m := range msgs { - if m.Message.From == addr { - max = int64(m.Message.Nonce) - } - } - - max++ // next unapplied nonce - - if max != -1 && uint64(max) != curnonce { - return 0, nil, xerrors.Errorf("tipset messages from %s have too low nonce %d, expected %d, h: %d", addr, max, curnonce, ts.Height()) - } - - return curnonce, &act.Balance, nil -} - func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof, pending []*types.SignedMessage) (*types.BlockMsg, error) { - msgs, err := selectMessages(context.TODO(), m.actorLookup, base, pending) + msgs, err := selectMessages(context.TODO(), m.api.StateGetActor, base, pending) if err != nil { return nil, xerrors.Errorf("message filtering failed: %w", err) } @@ -395,7 +360,7 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type return m.api.MinerCreateBlock(context.TODO(), addr, base.ts, ticket, proof, msgs, nheight, uint64(uts)) } -type actorLookup func(context.Context, address.Address, *types.TipSet) (uint64, *types.BigInt, error) +type actorLookup func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) func countFrom(msgs []*types.SignedMessage, from address.Address) (out int) { for _, msg := range msgs { @@ -424,13 +389,13 @@ func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs from := msg.Message.From if _, ok := inclNonces[from]; !ok { - nonce, balance, err := al(ctx, from, base.ts) + act, err := al(ctx, from, base.ts) if err != nil { return nil, xerrors.Errorf("failed to check message sender balance: %w", err) } - inclNonces[from] = nonce - inclBalances[from] = *balance + inclNonces[from] = act.Nonce + inclBalances[from] = act.Balance } if inclBalances[from].LessThan(msg.Message.RequiredFunds()) { diff --git a/miner/miner_test.go b/miner/miner_test.go index 47e9e6d4a..160433d72 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -33,8 +33,8 @@ func TestMessageFiltering(t *testing.T) { }, } - af := func(ctx context.Context, addr address.Address, ts *types.TipSet) (uint64, *types.BigInt, error) { - return actors[addr].Nonce, &actors[addr].Balance, nil + af := func(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, error) { + return actors[addr], nil } msgs := []types.Message{ diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 435e6b93e..1e39be598 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -68,7 +68,6 @@ func (a *ChainAPI) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api }, nil } -// TODO: Maybe deprecate in favor of just using ChainGetTipSetMessages? func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([]api.Message, error) { b, err := a.Chain.GetBlock(bcid) if err != nil { @@ -102,28 +101,6 @@ func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([] return out, nil } -func (a *ChainAPI) ChainGetTipSetMessages(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) { - ts, err := a.Chain.LoadTipSet(tsk.Cids()) - if err != nil { - return nil, xerrors.Errorf("failed to load tipset from key: %w", err) - } - - messages, err := a.Chain.MessagesForTipset(ts) - if err != nil { - return nil, xerrors.Errorf("getting messages for tipset: %w", err) - } - - var out []api.Message - for _, m := range messages { - out = append(out, api.Message{ - Cid: m.Cid(), - Message: m.VMMessage(), - }) - } - - return out, nil -} - func (a *ChainAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Cid) ([]*types.MessageReceipt, error) { b, err := a.Chain.GetBlock(bcid) if err != nil { From 569bcce8780fb016814c88ed1266f4b04d3ef213 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 3 Dec 2019 12:23:56 -0800 Subject: [PATCH 10/12] sorting is not necessary --- miner/miner.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index a5dc405c3..ad06acd01 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -2,7 +2,6 @@ package miner import ( "context" - "sort" "sync" "time" @@ -376,10 +375,6 @@ func selectMessages(ctx context.Context, al actorLookup, base *MiningBase, msgs inclNonces := make(map[address.Address]uint64) inclBalances := make(map[address.Address]types.BigInt) - sort.Slice(msgs, func(i, j int) bool { // TODO: is this actually needed? - return msgs[i].Message.Nonce < msgs[j].Message.Nonce - }) - for _, msg := range msgs { if msg.Message.To == address.Undef { log.Warnf("message in mempool had bad 'To' address") From d79f1c180d0da74f705354b6cd02c9e02562bf73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 22:09:39 +0100 Subject: [PATCH 11/12] mpool: Make tests pass --- chain/messagepool/messagepool.go | 6 ++++-- chain/messagepool/messagepool_test.go | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 38456a143..369be86f6 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -341,7 +341,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage) error { func (mp *MessagePool) GetNonce(addr address.Address) (uint64, error) { mp.curTsLk.Lock() - defer mp.curTsLk.Lock() + defer mp.curTsLk.Unlock() mp.lk.Lock() defer mp.lk.Unlock() @@ -415,7 +415,7 @@ func (mp *MessagePool) getStateBalance(addr address.Address) (types.BigInt, erro func (mp *MessagePool) PushWithNonce(addr address.Address, cb func(uint64) (*types.SignedMessage, error)) (*types.SignedMessage, error) { mp.curTsLk.Lock() - defer mp.curTsLk.Lock() + defer mp.curTsLk.Unlock() mp.lk.Lock() defer mp.lk.Unlock() @@ -534,6 +534,8 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) return err } + mp.curTs = pts + for _, msg := range msgs { if err := mp.addTs(msg, pts); err != nil { log.Error(err) // TODO: probably lots of spam in multi-block tsets diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 1cd8f8a75..8b18465b9 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -52,8 +52,9 @@ func (tma *testMpoolApi) setBlockMessages(h *types.BlockHeader, msgs ...*types.S tma.tipsets = append(tma.tipsets, mock.TipSet(h)) } -func (tma *testMpoolApi) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) { +func (tma *testMpoolApi) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { tma.cb = cb + return nil } func (tma *testMpoolApi) PutMessage(m store.ChainMsg) (cid.Cid, error) { @@ -216,7 +217,8 @@ func TestRevertMessages(t *testing.T) { assertNonce(t, mp, sender, 4) - if len(mp.Pending()) != 3 { + p, _ := mp.Pending() + if len(p) != 3 { t.Fatal("expected three messages in mempool") } From 9bb054a767f66464b046cac3e5b5c1e8fd035300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 3 Dec 2019 22:27:07 +0100 Subject: [PATCH 12/12] slightly cleaner IsRoundWinner --- chain/gen/gen.go | 26 +++++++++++++------------- miner/miner.go | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index db97dae32..059db2be5 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -261,11 +261,11 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add VRFProof: vrfout, } - win, eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], &mca{w: cg.w, sm: cg.sm}) + eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], &mca{w: cg.w, sm: cg.sm}) if err != nil { return nil, nil, xerrors.Errorf("checking round winner failed: %w", err) } - if !win { + if eproofin == nil { return nil, tick, nil } eproof, err := ComputeProof(ctx, cg.eppProvs[m], eproofin) @@ -477,28 +477,28 @@ type ProofInput struct { vrfout []byte } -func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (bool, *ProofInput, error) { +func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (*ProofInput, error) { r, err := a.ChainGetRandomness(ctx, ts.Key(), round-build.EcRandomnessLookback) if err != nil { - return false, nil, xerrors.Errorf("chain get randomness: %w", err) + return nil, xerrors.Errorf("chain get randomness: %w", err) } mworker, err := a.StateMinerWorker(ctx, miner, ts) if err != nil { - return false, nil, xerrors.Errorf("failed to get miner worker: %w", err) + return nil, xerrors.Errorf("failed to get miner worker: %w", err) } vrfout, err := ComputeVRF(ctx, a.WalletSign, mworker, miner, DSepElectionPost, r) if err != nil { - return false, nil, xerrors.Errorf("failed to compute VRF: %w", err) + return nil, xerrors.Errorf("failed to compute VRF: %w", err) } pset, err := a.StateMinerProvingSet(ctx, miner, ts) if err != nil { - return false, nil, xerrors.Errorf("failed to load proving set for miner: %w", err) + return nil, xerrors.Errorf("failed to load proving set for miner: %w", err) } if len(pset) == 0 { - return false, nil, nil + return nil, nil } var sinfos []ffi.PublicSectorInfo @@ -515,17 +515,17 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add hvrf := sha256.Sum256(vrfout) candidates, err := epp.GenerateCandidates(ctx, sectors, hvrf[:]) if err != nil { - return false, nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err) + return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err) } pow, err := a.StateMinerPower(ctx, miner, ts) if err != nil { - return false, nil, xerrors.Errorf("failed to check power: %w", err) + return nil, xerrors.Errorf("failed to check power: %w", err) } ssize, err := a.StateMinerSectorSize(ctx, miner, ts) if err != nil { - return false, nil, xerrors.Errorf("failed to look up miners sector size: %w", err) + return nil, xerrors.Errorf("failed to look up miners sector size: %w", err) } var winners []sectorbuilder.EPostCandidate @@ -537,10 +537,10 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add // no winners, sad if len(winners) == 0 { - return false, nil, nil + return nil, nil } - return true, &ProofInput{ + return &ProofInput{ sectors: sectors, hvrf: hvrf[:], winners: winners, diff --git a/miner/miner.go b/miner/miner.go index ad06acd01..b49c422d5 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -264,12 +264,12 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB return nil, xerrors.Errorf("scratching ticket failed: %w", err) } - win, proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(base.ts.Height()+base.nullRounds+1), addr, m.epp, m.api) + proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(base.ts.Height()+base.nullRounds+1), addr, m.epp, m.api) if err != nil { return nil, xerrors.Errorf("failed to check if we win next round: %w", err) } - if !win { + if proofin == nil { base.nullRounds++ return nil, nil }