From 11040f105b331c032b41e7a62f901ee0c74d0143 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 15:43:47 -0700 Subject: [PATCH 01/23] WIP: post scheduling --- chain/stmgr/stmgr.go | 15 +++++++----- chain/stmgr/utils.go | 54 +++++++++++++++++++++++++++++++++++++++++++- chain/store/store.go | 17 ++++++++++++-- go.mod | 2 +- go.sum | 2 ++ storage/miner.go | 37 +++++++++++++++++++++++++++++- 6 files changed, 116 insertions(+), 11 deletions(-) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 447c1bd63..03f14a371 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -120,8 +120,11 @@ func (sm *StateManager) computeTipSetState(cids []cid.Cid) (cid.Cid, error) { return vmi.Flush(ctx) } -func (sm *StateManager) GetActor(addr address.Address) (*types.Actor, error) { - ts := sm.cs.GetHeaviestTipSet() +func (sm *StateManager) GetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { + if ts == nil { + ts = sm.cs.GetHeaviestTipSet() + } + stcid, err := sm.TipSetState(ts.Cids()) if err != nil { return nil, xerrors.Errorf("tipset state: %w", err) @@ -136,8 +139,8 @@ func (sm *StateManager) GetActor(addr address.Address) (*types.Actor, error) { return state.GetActor(addr) } -func (sm *StateManager) GetBalance(addr address.Address) (types.BigInt, error) { - act, err := sm.GetActor(addr) +func (sm *StateManager) GetBalance(addr address.Address, ts *types.TipSet) (types.BigInt, error) { + act, err := sm.GetActor(addr, ts) if err != nil { return types.BigInt{}, xerrors.Errorf("get actor: %w", err) } @@ -149,8 +152,8 @@ func (sm *StateManager) ChainStore() *store.ChainStore { return sm.cs } -func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}) (*types.Actor, error) { - act, err := sm.GetActor(a) +func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) { + act, err := sm.GetActor(a, ts) if err != nil { return nil, err } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index da3f9e02d..addeb765f 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -2,12 +2,16 @@ package stmgr import ( "context" - "github.com/libp2p/go-libp2p-core/peer" "github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/types" + + amt "github.com/filecoin-project/go-amt-ipld" cid "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" ) @@ -122,3 +126,51 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad return peer.IDFromBytes(recp.Return) } + +func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) { + var mas actors.StorageMinerActorState + _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + if err != nil { + return 0, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + return mas.ProvingPeriodEnd, nil +} + +type SectorSetEntry struct { + SectorID uint64 + CommR []byte + CommD []byte +} + +func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]SectorSetEntry, error) { + var mas actors.StorageMinerActorState + _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + bs := amt.WrapBlockstore(sm.ChainStore().Blockstore()) + a, err := amt.LoadAMT(bs, mas.ProvingSet) + if err != nil { + return nil, err + } + + var sset []SectorSetEntry + if err := a.ForEach(func(i uint64, v *cbg.Deferred) error { + var comms [][]byte + if err := cbor.DecodeInto(v.Raw, &comms); err != nil { + return err + } + sset = append(sset, SectorSetEntry{ + SectorID: i, + CommR: comms[0], + CommD: comms[1], + }) + return nil + }); err != nil { + return nil, err + } + + return sset, nil +} diff --git a/chain/store/store.go b/chain/store/store.go index 590f5a402..1a6db9faa 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -35,6 +35,7 @@ type ChainStore struct { heaviest *types.TipSet bestTips *pubsub.PubSub + pubLk sync.Mutex tstLk sync.Mutex tipsets map[uint64][]cid.Cid @@ -51,6 +52,8 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore { } hcnf := func(rev, app []*types.TipSet) error { + cs.pubLk.Lock() + defer cs.pubLk.Unlock() for _, r := range rev { cs.bestTips.Pub(&HeadChange{ Type: HCRevert, @@ -122,8 +125,9 @@ func (cs *ChainStore) SubNewTips() chan *types.TipSet { } const ( - HCRevert = "revert" - HCApply = "apply" + HCRevert = "revert" + HCApply = "apply" + HCCurrent = "current" ) type HeadChange struct { @@ -132,8 +136,17 @@ type HeadChange struct { } func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan *HeadChange { + cs.pubLk.Lock() subch := cs.bestTips.Sub("headchange") + head := cs.GetHeaviestTipSet() + cs.pubLk.Unlock() + out := make(chan *HeadChange, 16) + out <- &HeadChange{ + Type: HCCurrent, + Val: head, + } + go func() { defer close(out) for { diff --git a/go.mod b/go.mod index 99c2e7e12..e44aed8be 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 github.com/BurntSushi/toml v0.3.1 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect - github.com/filecoin-project/go-amt-ipld v0.0.0-20190917010905-40ffeec492ae + github.com/filecoin-project/go-amt-ipld v0.0.0-20190917221444-2ed85149c65d github.com/filecoin-project/go-bls-sigs v0.0.0-20190718224239-4bc4b8a7bbf8 github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543 github.com/filecoin-project/go-sectorbuilder v0.0.0-00010101000000-000000000000 diff --git a/go.sum b/go.sum index 1059a4470..73c883c1c 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,8 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/filecoin-project/go-amt-ipld v0.0.0-20190917010905-40ffeec492ae h1:rSg6wenxKdXby0piY57Vv5gOJR6Eibqq/4PxEk6KjvE= github.com/filecoin-project/go-amt-ipld v0.0.0-20190917010905-40ffeec492ae/go.mod h1:lKjJYPg2kwbav5f78i5YA8kGccnZn18IySbpneXvaQs= +github.com/filecoin-project/go-amt-ipld v0.0.0-20190917221444-2ed85149c65d h1:fAJ40dcN0kpSFfdTssa1kLxlDImSEZy8e1d7a32tyBY= +github.com/filecoin-project/go-amt-ipld v0.0.0-20190917221444-2ed85149c65d/go.mod h1:lKjJYPg2kwbav5f78i5YA8kGccnZn18IySbpneXvaQs= github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543 h1:aMJGfgqe1QDhAVwxRg5fjCRF533xHidiKsugk7Vvzug= github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543/go.mod h1:mjrHv1cDGJWDlGmC0eDc1E5VJr8DmL9XMUcaFwiuKg8= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= diff --git a/storage/miner.go b/storage/miner.go index 9b4ff0ef2..293d8162a 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -170,7 +170,42 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal } func (m *Miner) runPoSt(ctx context.Context) { - log.Warning("dont care about posts yet") + notifs, err := m.api.ChainNotify(ctx) + if err != nil { + // TODO: this is probably 'crash the node' level serious + log.Errorf("POST ROUTINE FAILED: failed to get chain notifications stream: %s", err) + return + } + + curhead := <-notifs + if curhead.Type != store.HCCurrent { + // TODO: this is probably 'crash the node' level serious + log.Warning("expected to get current best tipset from chain notifications stream") + return + } + + postCtx, cancel := context.WithCancel(ctx) + postWaitCh, onBlock := m.maybeDoPost(postCtx, curhead) + + for { + select { + case <-ctx.Done(): + case ch, ok := <-notifs: + if !ok { + log.Warning("chain notifications stream terminated") + // TODO: attempt to restart it if the context isnt cancelled + return + } + + if ch.Type == store.HCApply { + m.maybeDoPost(ch.Val) + } + } + } +} + +func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error, *types.BlockHeader) { + } func (m *Miner) runPreflightChecks(ctx context.Context) error { From cc877f5c04a5949b5a492ac617a644541d685c02 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 17:08:49 -0700 Subject: [PATCH 02/23] WIP: expanding API to serve post producer needs --- api/api.go | 18 +++++++++--- api/struct.go | 46 +++++++++++++++++++----------- chain/stmgr/utils.go | 12 ++------ node/impl/full/chain.go | 4 +++ node/impl/full/state.go | 7 +++++ storage/miner.go | 63 +++++++++++++++++++++++++++-------------- storage/sector/store.go | 5 ++++ 7 files changed, 105 insertions(+), 50 deletions(-) diff --git a/api/api.go b/api/api.go index ee6c82661..696de369c 100644 --- a/api/api.go +++ b/api/api.go @@ -53,6 +53,7 @@ type FullNode interface { ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error) ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error) ChainGetBlockReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error) + ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) // messages @@ -101,15 +102,18 @@ type FullNode interface { //ClientListAsks() []Ask + // if tipset is nil, we'll use heaviest + StateCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) + StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) + StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) + StateMinerSectors(context.Context, address.Address) ([]*SectorInfo, error) StateMinerProvingSet(context.Context, address.Address) ([]*SectorInfo, error) StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error) StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) - // if tipset is nil, we'll use heaviest - StateCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) - StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) - StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) + StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) + StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]SectorSetEntry, error) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) PaychList(context.Context) ([]address.Address, error) @@ -269,3 +273,9 @@ type RetrievalOrder struct { Miner address.Address MinerPeerID peer.ID } + +type SectorSetEntry struct { + SectorID uint64 + CommR []byte + CommD []byte +} diff --git a/api/struct.go b/api/struct.go index 82f033ce6..91f20759d 100644 --- a/api/struct.go +++ b/api/struct.go @@ -39,14 +39,15 @@ type FullNodeStruct struct { CommonStruct Internal struct { - ChainNotify func(context.Context) (<-chan *store.HeadChange, error) `perm:"read"` - ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error `perm:"write"` - ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"` - ChainGetRandomness func(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) `perm:"read"` - ChainWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"` - ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"` - ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"` - ChainGetBlockReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` + ChainNotify func(context.Context) (<-chan *store.HeadChange, error) `perm:"read"` + ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error `perm:"write"` + ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"` + ChainGetRandomness func(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) `perm:"read"` + ChainWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"` + ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"` + ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"` + ChainGetBlockReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"` + ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"` MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"` MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"` @@ -75,14 +76,16 @@ type FullNodeStruct struct { ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"` ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"` - StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` - StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` - StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` - StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` - StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` - StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` - StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` - StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` + StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` + StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` + StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` + StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` + StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` + StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` + StateMinerProvingSet func(ctx context.Context, actor address.Address, ts *types.TipSet) ([]SectorSetEntry, error) `perm:"read"` + StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` + StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` + StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) `perm:"sign"` PaychList func(context.Context) ([]address.Address, error) `perm:"read"` @@ -230,6 +233,10 @@ func (c *FullNodeStruct) ChainWaitMsg(ctx context.Context, msgc cid.Cid) (*MsgWa return c.Internal.ChainWaitMsg(ctx, msgc) } +func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) { + return c.Internal.ChainGetTipSetByHeight(ctx, h, ts) +} + func (c *FullNodeStruct) WalletNew(ctx context.Context, typ string) (address.Address, error) { return c.Internal.WalletNew(ctx, typ) } @@ -297,6 +304,13 @@ func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) { return c.Internal.StateMinerPeerID(ctx, m, ts) } +func (c *FullNodeStruct) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { + return c.Internal.StateMinerProvingPeriodEnd(ctx, actor, ts) +} + +func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]SectorSetEntry, error) { + return c.Internal.StateMinerProvingSet(ctx, actor, ts) +} func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) { return c.Internal.StateCall(ctx, msg, ts) diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index addeb765f..a7a054e6d 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -137,13 +137,7 @@ func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.T return mas.ProvingPeriodEnd, nil } -type SectorSetEntry struct { - SectorID uint64 - CommR []byte - CommD []byte -} - -func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]SectorSetEntry, error) { +func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]api.SectorSetEntry, error) { var mas actors.StorageMinerActorState _, err := sm.LoadActorState(ctx, maddr, &mas, ts) if err != nil { @@ -156,13 +150,13 @@ func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, return nil, err } - var sset []SectorSetEntry + var sset []api.SectorSetEntry if err := a.ForEach(func(i uint64, v *cbg.Deferred) error { var comms [][]byte if err := cbor.DecodeInto(v.Raw, &comms); err != nil { return err } - sset = append(sset, SectorSetEntry{ + sset = append(sset, api.SectorSetEntry{ SectorID: i, CommR: comms[0], CommD: comms[1], diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 0743cff55..cbfc11ff4 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -108,3 +108,7 @@ func (a *ChainAPI) ChainGetBlockReceipts(ctx context.Context, bcid cid.Cid) ([]* return out, nil } + +func (a *ChainAPI) ChainGetTipSetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) { + panic("NYI") +} diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 6b9bfe33d..11f6cf6dd 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -190,6 +190,13 @@ func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts * return stmgr.GetMinerPeerID(ctx, a.StateManager, ts, m) } +func (a *StateAPI) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { + return stmgr.GetMinerProvingPeriodEnd(ctx, a.StateManager, ts, actor) +} + +func (a *StateAPI) StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]api.SectorSetEntry, error) { + return stmgr.GetMinerProvingSet(ctx, a.StateManager, ts, actor) +} func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) { return a.StateManager.Call(ctx, msg, ts) } diff --git a/storage/miner.go b/storage/miner.go index 293d8162a..a02a7c3be 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -44,12 +44,17 @@ type storageMinerApi interface { // Call a read only method on actors (no interaction with the chain required) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) + StateMinerWorker(ctx context.Context, address.Address, ts *types.TipSet) (address.Address, error) + StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) + StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]api.SectorSetEntry, error) MpoolPush(context.Context, *types.SignedMessage) error MpoolGetNonce(context.Context, address.Address) (uint64, error) ChainWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) ChainNotify(context.Context) (<-chan *store.HeadChange, error) + ChainGetRandomness(context.Context, ts *types.TipSet, []*types.Ticket, int) ([]byte, error) + ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) WalletBalance(context.Context, address.Address) (types.BigInt, error) WalletSign(context.Context, address.Address, []byte) (*types.Signature, error) @@ -204,12 +209,47 @@ func (m *Miner) runPoSt(ctx context.Context) { } } -func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error, *types.BlockHeader) { +func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error, *types.BlockHeader, error) { + ppe, err := m.api.StateMinerProvingPeriodEnd(ctx, m.actor, ts) + if err != nil { + return nil, nil, xerrors.Errorf("failed to get proving period end for miner: %w", err) + } + if ppe < ts.Height() { + return nil, nil, nil + } + + sset, err := m.api.StateMinerProvingSet(ctx, m.actor, ts) + if err != nil { + return nil, nil, xerrors.Errorf("failed to get proving set for miner: %w", err) + } + + r, err := m.api.ChainGetRandomness(ctx, ts, nil, ts.Height() - ppe) + if err != nil { + return nil, nil, xerrors.Errorf("failed to get chain randomness for post: %w", err) + } + + sourceTs, err := m.api.ChainGetTipSetByHeight(ctx, ppe, ts) + if err != nil { + return nil, nil, xerrors.Errorf("failed to get post start tipset: %w", err) + } + + ret := make(chan error, 1) + go func() { + proof, err := s.secst.RunPoSt(ctx, sset, r) + if err != nil { + ret <- xerrors.Errorf("running post failed: %w", err) + return + } + + panic("submit post maybe?") +}() + + return ret, sourceTs.MinTicketBlock(), nil } func (m *Miner) runPreflightChecks(ctx context.Context) error { - worker, err := m.getWorkerAddr(ctx) + worker, err := m.api.StateMinerWorker(ctx, m.maddr, nil) if err != nil { return err } @@ -229,22 +269,3 @@ func (m *Miner) runPreflightChecks(ctx context.Context) error { return nil } -func (m *Miner) getWorkerAddr(ctx context.Context) (address.Address, error) { - msg := &types.Message{ - To: m.maddr, - From: m.maddr, // it doesnt like it if we dont give it a from... probably should fix that - Method: actors.MAMethods.GetWorkerAddr, - Params: nil, - } - - recpt, err := m.api.StateCall(ctx, msg, nil) - if err != nil { - return address.Undef, errors.Wrapf(err, "calling getWorker(%s)", m.maddr) - } - - if recpt.ExitCode != 0 { - return address.Undef, fmt.Errorf("failed to call getWorker(%s): return %d", m.maddr, recpt.ExitCode) - } - - return address.NewFromBytes(recpt.Return) -} diff --git a/storage/sector/store.go b/storage/sector/store.go index 3d18e77ad..115dbe20f 100644 --- a/storage/sector/store.go +++ b/storage/sector/store.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/lib/sectorbuilder" logging "github.com/ipfs/go-log" @@ -162,6 +163,10 @@ func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.Sect return s.sb.SealStatus(sector) } +func (s *Store) RunPoSt(ctx context.Context, sectors []api.SectorSetEntry, r []byte) ([]byte, error) { + panic("NYI") +} + func (s *Store) Stop() { close(s.closeCh) } From b1e77748e723d2cd46a25b23df395c5d7a85cc3b Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 19:50:03 -0700 Subject: [PATCH 03/23] scaffolding and refactoring to make post scheduler work --- api/api.go | 14 +---- api/struct.go | 36 +++++------- chain/cbor_gen.go | 106 ---------------------------------- chain/messagepool.go | 5 +- chain/stmgr/utils.go | 7 ++- chain/sub/incoming.go | 3 +- chain/{ => types}/blockmsg.go | 6 +- chain/types/cbor_gen.go | 106 ++++++++++++++++++++++++++++++++++ chain/types/tipset.go | 9 +++ cli/state.go | 2 +- gen/main.go | 2 +- miner/miner.go | 5 +- node/impl/full/chain.go | 3 +- node/impl/full/state.go | 66 ++------------------- node/impl/full/wallet.go | 2 +- paych/paych.go | 2 +- storage/miner.go | 71 +++++++++++++++++------ storage/sector/store.go | 2 +- 18 files changed, 208 insertions(+), 239 deletions(-) rename chain/{ => types}/blockmsg.go (83%) diff --git a/api/api.go b/api/api.go index 696de369c..a924379b2 100644 --- a/api/api.go +++ b/api/api.go @@ -9,7 +9,6 @@ import ( "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" - "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" @@ -47,7 +46,7 @@ type FullNode interface { // chain ChainNotify(context.Context) (<-chan *store.HeadChange, error) ChainHead(context.Context) (*types.TipSet, error) // TODO: check serialization - ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error // TODO: check serialization + ChainSubmitBlock(ctx context.Context, blk *types.BlockMsg) error // TODO: check serialization ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) ChainWaitMsg(context.Context, cid.Cid) (*MsgWait, error) ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error) @@ -69,7 +68,7 @@ type FullNode interface { MinerRegister(context.Context, address.Address) error MinerUnregister(context.Context, address.Address) error MinerAddresses(context.Context) ([]address.Address, error) - MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*chain.BlockMsg, error) + MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*types.BlockMsg, error) // // UX ? @@ -108,12 +107,11 @@ type FullNode interface { StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) StateMinerSectors(context.Context, address.Address) ([]*SectorInfo, error) - StateMinerProvingSet(context.Context, address.Address) ([]*SectorInfo, error) + StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error) StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) - StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]SectorSetEntry, error) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) PaychList(context.Context) ([]address.Address, error) @@ -273,9 +271,3 @@ type RetrievalOrder struct { Miner address.Address MinerPeerID peer.ID } - -type SectorSetEntry struct { - SectorID uint64 - CommR []byte - CommD []byte -} diff --git a/api/struct.go b/api/struct.go index 91f20759d..0a1c6f4d5 100644 --- a/api/struct.go +++ b/api/struct.go @@ -5,7 +5,6 @@ import ( "github.com/libp2p/go-libp2p-core/network" - "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" @@ -40,7 +39,7 @@ type FullNodeStruct struct { Internal struct { ChainNotify func(context.Context) (<-chan *store.HeadChange, error) `perm:"read"` - ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error `perm:"write"` + ChainSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"` ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"` ChainGetRandomness func(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) `perm:"read"` ChainWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"` @@ -56,7 +55,7 @@ type FullNodeStruct struct { MinerRegister func(context.Context, address.Address) error `perm:"admin"` MinerUnregister func(context.Context, address.Address) error `perm:"admin"` MinerAddresses func(context.Context) ([]address.Address, error) `perm:"write"` - MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*chain.BlockMsg, error) `perm:"write"` + MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*types.BlockMsg, error) `perm:"write"` WalletNew func(context.Context, string) (address.Address, error) `perm:"write"` WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"` @@ -76,16 +75,15 @@ type FullNodeStruct struct { ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"` ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"` - StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` - StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` - StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` - StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` - StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` - StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` - StateMinerProvingSet func(ctx context.Context, actor address.Address, ts *types.TipSet) ([]SectorSetEntry, error) `perm:"read"` - StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` - StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` - StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` + StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` + StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) `perm:"read"` + StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` + StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` + StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` + StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` + StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` + StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` + StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) `perm:"sign"` PaychList func(context.Context) ([]address.Address, error) `perm:"read"` @@ -213,11 +211,11 @@ func (c *FullNodeStruct) MinerAddresses(ctx context.Context) ([]address.Address, return c.Internal.MinerAddresses(ctx) } -func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*chain.BlockMsg, error) { +func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*types.BlockMsg, error) { return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs, ts) } -func (c *FullNodeStruct) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error { +func (c *FullNodeStruct) ChainSubmitBlock(ctx context.Context, blk *types.BlockMsg) error { return c.Internal.ChainSubmitBlock(ctx, blk) } @@ -289,8 +287,8 @@ func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Add return c.Internal.StateMinerSectors(ctx, addr) } -func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address) ([]*SectorInfo, error) { - return c.Internal.StateMinerProvingSet(ctx, addr) +func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*SectorInfo, error) { + return c.Internal.StateMinerProvingSet(ctx, addr, ts) } func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, ts *types.TipSet) (MinerPower, error) { @@ -308,10 +306,6 @@ func (c *FullNodeStruct) StateMinerProvingPeriodEnd(ctx context.Context, actor a return c.Internal.StateMinerProvingPeriodEnd(ctx, actor, ts) } -func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]SectorSetEntry, error) { - return c.Internal.StateMinerProvingSet(ctx, actor, ts) -} - func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) { return c.Internal.StateCall(ctx, msg, ts) } diff --git a/chain/cbor_gen.go b/chain/cbor_gen.go index 0a263e20a..e7f2a40b8 100644 --- a/chain/cbor_gen.go +++ b/chain/cbor_gen.go @@ -472,109 +472,3 @@ func (t *BSTipSet) UnmarshalCBOR(br io.Reader) error { return nil } - -func (t *BlockMsg) MarshalCBOR(w io.Writer) error { - if _, err := w.Write([]byte{131}); err != nil { - return err - } - - // t.t.Header (types.BlockHeader) - if err := t.Header.MarshalCBOR(w); err != nil { - return err - } - - // t.t.BlsMessages ([]cid.Cid) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.BlsMessages)))); err != nil { - return err - } - for _, v := range t.BlsMessages { - if err := cbg.WriteCid(w, v); err != nil { - return xerrors.Errorf("failed writing cid field t.BlsMessages: %w", err) - } - } - - // t.t.SecpkMessages ([]cid.Cid) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.SecpkMessages)))); err != nil { - return err - } - for _, v := range t.SecpkMessages { - if err := cbg.WriteCid(w, v); err != nil { - return xerrors.Errorf("failed writing cid field t.SecpkMessages: %w", err) - } - } - return nil -} - -func (t *BlockMsg) UnmarshalCBOR(br io.Reader) error { - - maj, extra, err := cbg.CborReadHeader(br) - if err != nil { - return err - } - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 3 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.t.Header (types.BlockHeader) - - t.Header = new(types.BlockHeader) - - if err := t.Header.UnmarshalCBOR(br); err != nil { - return err - } - // t.t.BlsMessages ([]cid.Cid) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if extra > 8192 { - return fmt.Errorf("array too large") - } - - if maj != cbg.MajArray { - return fmt.Errorf("expected cbor array") - } - if extra > 0 { - t.BlsMessages = make([]cid.Cid, extra) - } - for i := 0; i < int(extra); i++ { - - c, err := cbg.ReadCid(br) - if err != nil { - return xerrors.Errorf("reading cid field t.BlsMessages failed: %w", err) - } - t.BlsMessages[i] = c - } - - // t.t.SecpkMessages ([]cid.Cid) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if extra > 8192 { - return fmt.Errorf("array too large") - } - - if maj != cbg.MajArray { - return fmt.Errorf("expected cbor array") - } - if extra > 0 { - t.SecpkMessages = make([]cid.Cid, extra) - } - for i := 0; i < int(extra); i++ { - - c, err := cbg.ReadCid(br) - if err != nil { - return xerrors.Errorf("reading cid field t.SecpkMessages failed: %w", err) - } - t.SecpkMessages[i] = c - } - - return nil -} diff --git a/chain/messagepool.go b/chain/messagepool.go index bbffd45a5..4ebde3512 100644 --- a/chain/messagepool.go +++ b/chain/messagepool.go @@ -2,9 +2,10 @@ package chain import ( "encoding/base64" - pubsub "github.com/libp2p/go-libp2p-pubsub" "sync" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/stmgr" "github.com/filecoin-project/go-lotus/chain/types" @@ -109,7 +110,7 @@ func (mp *MessagePool) getNonceLocked(addr address.Address) (uint64, error) { return mset.startNonce + uint64(len(mset.msgs)), nil } - act, err := mp.sm.GetActor(addr) + act, err := mp.sm.GetActor(addr, nil) if err != nil { return 0, err } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index a7a054e6d..bde2446e5 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -3,6 +3,7 @@ package stmgr import ( "context" + "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/types" @@ -137,7 +138,7 @@ func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.T return mas.ProvingPeriodEnd, nil } -func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]api.SectorSetEntry, error) { +func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.SectorInfo, error) { var mas actors.StorageMinerActorState _, err := sm.LoadActorState(ctx, maddr, &mas, ts) if err != nil { @@ -150,13 +151,13 @@ func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, return nil, err } - var sset []api.SectorSetEntry + var sset []*api.SectorInfo if err := a.ForEach(func(i uint64, v *cbg.Deferred) error { var comms [][]byte if err := cbor.DecodeInto(v.Raw, &comms); err != nil { return err } - sset = append(sset, api.SectorSetEntry{ + sset = append(sset, &api.SectorInfo{ SectorID: i, CommR: comms[0], CommD: comms[1], diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index d41eac887..5bcadf16f 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -2,6 +2,7 @@ package sub import ( "context" + logging "github.com/ipfs/go-log" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -23,7 +24,7 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha continue } - blk, err := chain.DecodeBlockMsg(msg.GetData()) + blk, err := types.DecodeBlockMsg(msg.GetData()) if err != nil { log.Error("got invalid block over pubsub: ", err) continue diff --git a/chain/blockmsg.go b/chain/types/blockmsg.go similarity index 83% rename from chain/blockmsg.go rename to chain/types/blockmsg.go index 22afced32..f3114499d 100644 --- a/chain/blockmsg.go +++ b/chain/types/blockmsg.go @@ -1,15 +1,13 @@ -package chain +package types import ( "bytes" "github.com/ipfs/go-cid" - - "github.com/filecoin-project/go-lotus/chain/types" ) type BlockMsg struct { - Header *types.BlockHeader + Header *BlockHeader BlsMessages []cid.Cid SecpkMessages []cid.Cid } diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 81a23081c..a2df6b3ff 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -1197,3 +1197,109 @@ func (t *MessageReceipt) UnmarshalCBOR(r io.Reader) error { } return nil } + +func (t *BlockMsg) MarshalCBOR(w io.Writer) error { + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.t.Header (types.BlockHeader) + if err := t.Header.MarshalCBOR(w); err != nil { + return err + } + + // t.t.BlsMessages ([]cid.Cid) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.BlsMessages)))); err != nil { + return err + } + for _, v := range t.BlsMessages { + if err := cbg.WriteCid(w, v); err != nil { + return xerrors.Errorf("failed writing cid field t.BlsMessages: %w", err) + } + } + + // t.t.SecpkMessages ([]cid.Cid) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.SecpkMessages)))); err != nil { + return err + } + for _, v := range t.SecpkMessages { + if err := cbg.WriteCid(w, v); err != nil { + return xerrors.Errorf("failed writing cid field t.SecpkMessages: %w", err) + } + } + return nil +} + +func (t *BlockMsg) UnmarshalCBOR(br io.Reader) error { + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Header (types.BlockHeader) + + t.Header = new(BlockHeader) + + if err := t.Header.UnmarshalCBOR(br); err != nil { + return err + } + // t.t.BlsMessages ([]cid.Cid) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("array too large") + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.BlsMessages = make([]cid.Cid, extra) + } + for i := 0; i < int(extra); i++ { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("reading cid field t.BlsMessages failed: %w", err) + } + t.BlsMessages[i] = c + } + + // t.t.SecpkMessages ([]cid.Cid) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("array too large") + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.SecpkMessages = make([]cid.Cid, extra) + } + for i := 0; i < int(extra); i++ { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("reading cid field t.SecpkMessages failed: %w", err) + } + t.SecpkMessages[i] = c + } + + return nil +} diff --git a/chain/types/tipset.go b/chain/types/tipset.go index 2d763650a..5484b476a 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -128,3 +128,12 @@ func (ts *TipSet) MinTicketBlock() *BlockHeader { return min } + +func (ts *TipSet) Contains(oc cid.Cid) bool { + for _, c := range ts.cids { + if c == oc { + return true + } + } + return false +} diff --git a/cli/state.go b/cli/state.go index ce799093f..970a48d05 100644 --- a/cli/state.go +++ b/cli/state.go @@ -104,7 +104,7 @@ var stateProvingSetCmd = &cli.Command{ return err } - sectors, err := api.StateMinerProvingSet(ctx, maddr) + sectors, err := api.StateMinerProvingSet(ctx, maddr, nil) if err != nil { return err } diff --git a/gen/main.go b/gen/main.go index 56323cde3..1ef741e5c 100644 --- a/gen/main.go +++ b/gen/main.go @@ -21,6 +21,7 @@ func main() { types.Merge{}, types.Actor{}, types.MessageReceipt{}, + types.BlockMsg{}, ) if err != nil { fmt.Println(err) @@ -32,7 +33,6 @@ func main() { chain.BlockSyncRequest{}, chain.BlockSyncResponse{}, chain.BSTipSet{}, - chain.BlockMsg{}, ) if err != nil { fmt.Println(err) diff --git a/miner/miner.go b/miner/miner.go index cf2b0e4ef..b9e1c04b1 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -6,7 +6,6 @@ import ( "time" "github.com/filecoin-project/go-lotus/build" - chain "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/gen" @@ -191,7 +190,7 @@ func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) { }, nil } -func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg, error) { +func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, error) { log.Debug("attempting to mine a block on:", base.ts.Cids()) ticket, err := m.scratchTicket(ctx, base) if err != nil { @@ -288,7 +287,7 @@ func (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (*types.Tic }, nil } -func (m *Miner) createBlock(base *MiningBase, ticket *types.Ticket, proof types.ElectionProof) (*chain.BlockMsg, error) { +func (m *Miner) createBlock(base *MiningBase, ticket *types.Ticket, proof types.ElectionProof) (*types.BlockMsg, error) { pending, err := m.api.MpoolPending(context.TODO(), base.ts) if err != nil { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index cbfc11ff4..2e429dde0 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -4,7 +4,6 @@ import ( "context" "github.com/filecoin-project/go-lotus/api" - "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" "golang.org/x/xerrors" @@ -27,7 +26,7 @@ func (a *ChainAPI) ChainNotify(ctx context.Context) (<-chan *store.HeadChange, e return a.Chain.SubHeadChanges(ctx), nil } -func (a *ChainAPI) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error { +func (a *ChainAPI) ChainSubmitBlock(ctx context.Context, blk *types.BlockMsg) error { if err := a.Chain.AddBlock(blk.Header); err != nil { return xerrors.Errorf("AddBlock failed: %w", err) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 11f6cf6dd..f7d49384c 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -12,7 +12,6 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-lotus/api" - "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/gen" @@ -94,62 +93,8 @@ func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address) return sinfos, nil } -func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address) ([]*api.SectorInfo, error) { - ts := a.Chain.GetHeaviestTipSet() - - stc, err := a.StateManager.TipSetState(ts.Cids()) - if err != nil { - return nil, err - } - - cst := hamt.CSTFromBstore(a.Chain.Blockstore()) - - st, err := state.LoadStateTree(cst, stc) - if err != nil { - return nil, err - } - - act, err := st.GetActor(addr) - if err != nil { - return nil, err - } - - var minerState actors.StorageMinerActorState - if err := cst.Get(ctx, act.Head, &minerState); err != nil { - return nil, err - } - - nd, err := hamt.LoadNode(ctx, cst, minerState.ProvingSet) - if err != nil { - return nil, err - } - - var sinfos []*api.SectorInfo - // Note to self: the hamt isnt a great data structure to use here... need to implement the sector set - err = nd.ForEach(ctx, func(k string, val interface{}) error { - sid, err := strconv.ParseUint(k, 10, 64) - if err != nil { - return err - } - - bval, ok := val.([]byte) - if !ok { - return fmt.Errorf("expected to get bytes in sector set hamt") - } - - var comms [][]byte - if err := cbor.DecodeInto(bval, &comms); err != nil { - return err - } - - sinfos = append(sinfos, &api.SectorInfo{ - SectorID: sid, - CommR: comms[0], - CommD: comms[1], - }) - return nil - }) - return sinfos, nil +func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.SectorInfo, error) { + return stmgr.GetMinerProvingSet(ctx, a.StateManager, ts, addr) } func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) { @@ -194,9 +139,6 @@ func (a *StateAPI) StateMinerProvingPeriodEnd(ctx context.Context, actor address return stmgr.GetMinerProvingPeriodEnd(ctx, a.StateManager, ts, actor) } -func (a *StateAPI) StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]api.SectorSetEntry, error) { - return stmgr.GetMinerProvingSet(ctx, a.StateManager, ts, actor) -} func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) { return a.StateManager.Call(ctx, msg, ts) } @@ -248,13 +190,13 @@ func (a *StateAPI) StateReadState(ctx context.Context, act *types.Actor, ts *typ } // This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner -func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*chain.BlockMsg, error) { +func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*types.BlockMsg, error) { fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, addr, parents, tickets, proof, msgs, ts) if err != nil { return nil, err } - var out chain.BlockMsg + var out types.BlockMsg out.Header = fblk.Header for _, msg := range fblk.BlsMessages { out.BlsMessages = append(out.BlsMessages, msg.Cid()) diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index 38803460f..6f02f7ff5 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -32,7 +32,7 @@ func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) { } func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { - return a.StateManager.GetBalance(addr) + return a.StateManager.GetBalance(addr, nil) } func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*types.Signature, error) { diff --git a/paych/paych.go b/paych/paych.go index 07dd8cbf8..5b0889be9 100644 --- a/paych/paych.go +++ b/paych/paych.go @@ -223,7 +223,7 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address func (pm *Manager) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *actors.PaymentChannelActorState, error) { var pcast actors.PaymentChannelActorState - act, err := pm.sm.LoadActorState(ctx, ch, &pcast) + act, err := pm.sm.LoadActorState(ctx, ch, &pcast, nil) if err != nil { return nil, nil, err } diff --git a/storage/miner.go b/storage/miner.go index a02a7c3be..e17a1806f 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -2,13 +2,13 @@ package storage import ( "context" - "fmt" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log" host "github.com/libp2p/go-libp2p-core/host" "github.com/pkg/errors" + "golang.org/x/xerrors" "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/build" @@ -44,16 +44,16 @@ type storageMinerApi interface { // Call a read only method on actors (no interaction with the chain required) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) - StateMinerWorker(ctx context.Context, address.Address, ts *types.TipSet) (address.Address, error) - StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) - StateMinerProvingSet(ctx context.Context, actor address.Address, ts *types.TipSet) ([]api.SectorSetEntry, error) + StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) + StateMinerProvingPeriodEnd(context.Context, address.Address, *types.TipSet) (uint64, error) + StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.SectorInfo, error) MpoolPush(context.Context, *types.SignedMessage) error MpoolGetNonce(context.Context, address.Address) (uint64, error) ChainWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) ChainNotify(context.Context) (<-chan *store.HeadChange, error) - ChainGetRandomness(context.Context, ts *types.TipSet, []*types.Ticket, int) ([]byte, error) + ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) WalletBalance(context.Context, address.Address) (types.BigInt, error) @@ -175,6 +175,7 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal } func (m *Miner) runPoSt(ctx context.Context) { + // TODO: most of this method can probably be replaced by the events module once it works on top of the api notifs, err := m.api.ChainNotify(ctx) if err != nil { // TODO: this is probably 'crash the node' level serious @@ -190,7 +191,11 @@ func (m *Miner) runPoSt(ctx context.Context) { } postCtx, cancel := context.WithCancel(ctx) - postWaitCh, onBlock := m.maybeDoPost(postCtx, curhead) + postWaitCh, onBlock, err := m.maybeDoPost(postCtx, curhead.Val) + if err != nil { + log.Errorf("initial 'maybeDoPost' call failed: %s", err) + return + } for { select { @@ -202,15 +207,39 @@ func (m *Miner) runPoSt(ctx context.Context) { return } - if ch.Type == store.HCApply { - m.maybeDoPost(ch.Val) + switch ch.Type { + case store.HCApply: + postWaitCh, onBlock, err = m.maybeDoPost(postCtx, ch.Val) + if err != nil { + log.Errorf("maybeDoPost failed: %s", err) + return + } + case store.HCRevert: + if onBlock != nil { + if ch.Val.Contains(onBlock.Cid()) { + // Our post may now be invalid! + cancel() // probably the right thing to do? + } + } + case store.HCCurrent: + log.Warn("got 'current' chain notification in middle of stream") } + case perr := <-postWaitCh: + if perr != nil { + log.Errorf("got error back from postWaitCh: %s", err) + // TODO: what do we even do here? + return + } + postWaitCh = nil + onBlock = nil + // yay? + log.Infof("post successfully submitted") } } } func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error, *types.BlockHeader, error) { - ppe, err := m.api.StateMinerProvingPeriodEnd(ctx, m.actor, ts) + ppe, err := m.api.StateMinerProvingPeriodEnd(ctx, m.maddr, ts) if err != nil { return nil, nil, xerrors.Errorf("failed to get proving period end for miner: %w", err) } @@ -219,12 +248,12 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return nil, nil, nil } - sset, err := m.api.StateMinerProvingSet(ctx, m.actor, ts) + sset, err := m.api.StateMinerProvingSet(ctx, m.maddr, ts) if err != nil { return nil, nil, xerrors.Errorf("failed to get proving set for miner: %w", err) } - r, err := m.api.ChainGetRandomness(ctx, ts, nil, ts.Height() - ppe) + r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(ts.Height()-ppe)) if err != nil { return nil, nil, xerrors.Errorf("failed to get chain randomness for post: %w", err) } @@ -236,14 +265,19 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error ret := make(chan error, 1) go func() { - proof, err := s.secst.RunPoSt(ctx, sset, r) - if err != nil { - ret <- xerrors.Errorf("running post failed: %w", err) - return - } + proof, err := m.secst.RunPoSt(ctx, sset, r) + if err != nil { + ret <- xerrors.Errorf("running post failed: %w", err) + return + } - panic("submit post maybe?") -}() + // TODO: submit post... + _ = proof + + // make sure it succeeds... + // m.api.ChainWaitMsg() + + }() return ret, sourceTs.MinTicketBlock(), nil } @@ -268,4 +302,3 @@ func (m *Miner) runPreflightChecks(ctx context.Context) error { log.Infof("starting up miner %s, worker addr %s", m.maddr, m.worker) return nil } - diff --git a/storage/sector/store.go b/storage/sector/store.go index 115dbe20f..cbad8917c 100644 --- a/storage/sector/store.go +++ b/storage/sector/store.go @@ -163,7 +163,7 @@ func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.Sect return s.sb.SealStatus(sector) } -func (s *Store) RunPoSt(ctx context.Context, sectors []api.SectorSetEntry, r []byte) ([]byte, error) { +func (s *Store) RunPoSt(ctx context.Context, sectors []*api.SectorInfo, r []byte) ([]byte, error) { panic("NYI") } From 976381010068ea54d23ff4e17b4b820129cee088 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 19:55:51 -0700 Subject: [PATCH 04/23] cleaup, small refactor --- chain/stmgr/utils.go | 19 +++++++++++++++++-- chain/sync_test.go | 5 ++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index bde2446e5..a9707acc9 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -10,6 +10,7 @@ import ( amt "github.com/filecoin-project/go-amt-ipld" cid "github.com/ipfs/go-cid" + blockstore "github.com/ipfs/go-ipfs-blockstore" cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p-core/peer" cbg "github.com/whyrusleeping/cbor-gen" @@ -145,8 +146,22 @@ func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, return nil, xerrors.Errorf("failed to load miner actor state: %w", err) } - bs := amt.WrapBlockstore(sm.ChainStore().Blockstore()) - a, err := amt.LoadAMT(bs, mas.ProvingSet) + return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.ProvingSet) +} + +func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.SectorInfo, error) { + var mas actors.StorageMinerActorState + _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors) +} + +func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid) ([]*api.SectorInfo, error) { + blks := amt.WrapBlockstore(bs) + a, err := amt.LoadAMT(blks, ssc) if err != nil { return nil, err } diff --git a/chain/sync_test.go b/chain/sync_test.go index 75247493d..56f98cc7d 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-lotus/api" - "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/gen" "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" @@ -105,8 +104,8 @@ func (tu *syncTestUtil) mineNewBlock(src int) { } } -func fblkToBlkMsg(fb *types.FullBlock) *chain.BlockMsg { - out := &chain.BlockMsg{ +func fblkToBlkMsg(fb *types.FullBlock) *types.BlockMsg { + out := &types.BlockMsg{ Header: fb.Header, } From 02887a63a30471a9fd533b1c3f6a47eb4f39b719 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 20:14:51 -0700 Subject: [PATCH 05/23] simplify stateminersectors impl --- node/impl/full/state.go | 59 +---------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/node/impl/full/state.go b/node/impl/full/state.go index f7d49384c..26761f505 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -2,11 +2,8 @@ package full import ( "context" - "fmt" - "strconv" "github.com/ipfs/go-hamt-ipld" - cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p-core/peer" "go.uber.org/fx" "golang.org/x/xerrors" @@ -36,61 +33,7 @@ type StateAPI struct { } func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address) ([]*api.SectorInfo, error) { - ts := a.StateManager.ChainStore().GetHeaviestTipSet() - - stc, err := a.StateManager.TipSetState(ts.Cids()) - if err != nil { - return nil, err - } - - cst := hamt.CSTFromBstore(a.StateManager.ChainStore().Blockstore()) - - st, err := state.LoadStateTree(cst, stc) - if err != nil { - return nil, err - } - - act, err := st.GetActor(addr) - if err != nil { - return nil, err - } - - var minerState actors.StorageMinerActorState - if err := cst.Get(ctx, act.Head, &minerState); err != nil { - return nil, err - } - - nd, err := hamt.LoadNode(ctx, cst, minerState.Sectors) - if err != nil { - return nil, err - } - - var sinfos []*api.SectorInfo - // Note to self: the hamt isnt a great data structure to use here... need to implement the sector set - err = nd.ForEach(ctx, func(k string, val interface{}) error { - sid, err := strconv.ParseUint(k, 10, 64) - if err != nil { - return err - } - - bval, ok := val.([]byte) - if !ok { - return fmt.Errorf("expected to get bytes in sector set hamt") - } - - var comms [][]byte - if err := cbor.DecodeInto(bval, &comms); err != nil { - return err - } - - sinfos = append(sinfos, &api.SectorInfo{ - SectorID: sid, - CommR: comms[0], - CommD: comms[1], - }) - return nil - }) - return sinfos, nil + return stmgr.GetMinerSectorSet(ctx, a.StateManager, nil, addr) } func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.SectorInfo, error) { From f2f60c029bc1bf59c02f08a872c91a2d49e93372 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 20:25:12 -0700 Subject: [PATCH 06/23] Add impl for GetTipsetByHeight --- chain/store/store.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/chain/store/store.go b/chain/store/store.go index 1a6db9faa..43c39991d 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -746,3 +746,26 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tick nextCids = mtb.Parents } } + +func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) { + if ts == nil { + ts = cs.GetHeaviestTipSet() + } + + if h > ts.Height() { + return nil, xerrors.Errorf("looking for tipset with height less than start point") + } + + for { + mtb := ts.MinTicketBlock() + if h >= ts.Height()-uint64(len(mtb.Tickets)) { + return ts, nil + } + + pts, err := cs.LoadTipSet(ts.Parents()) + if err != nil { + return nil, err + } + ts = pts + } +} From 3e45088812536cd5132f70e28312bba4fbd9e53d Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 17 Sep 2019 20:32:52 -0700 Subject: [PATCH 07/23] cleaning up a few types --- lib/sectorbuilder/sectorbuilder.go | 4 +++- storage/miner.go | 3 ++- storage/sector/store.go | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/sectorbuilder/sectorbuilder.go b/lib/sectorbuilder/sectorbuilder.go index ee7e4aecb..3c11ffebd 100644 --- a/lib/sectorbuilder/sectorbuilder.go +++ b/lib/sectorbuilder/sectorbuilder.go @@ -17,6 +17,8 @@ type SectorSealingStatus = sectorbuilder.SectorSealingStatus type StagedSectorMetadata = sectorbuilder.StagedSectorMetadata +type SortedSectorInfo = sectorbuilder.SortedSectorInfo + const CommLen = sectorbuilder.CommitmentBytesLen type SectorBuilder struct { @@ -81,7 +83,7 @@ func (sb *SectorBuilder) GetAllStagedSectors() ([]StagedSectorMetadata, error) { return sectorbuilder.GetAllStagedSectors(sb.handle) } -func (sb *SectorBuilder) GeneratePoSt(sectorInfo sectorbuilder.SortedSectorInfo, challengeSeed [CommLen]byte, faults []uint64) ([]byte, error) { +func (sb *SectorBuilder) GeneratePoSt(sectorInfo SortedSectorInfo, challengeSeed [CommLen]byte, faults []uint64) ([]byte, error) { // Wait, this is a blocking method with no way of interrupting it? // does it checkpoint itself? return sectorbuilder.GeneratePoSt(sb.handle, sectorInfo, challengeSeed, faults) diff --git a/storage/miner.go b/storage/miner.go index e17a1806f..2d3278c9f 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -265,7 +265,8 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error ret := make(chan error, 1) go func() { - proof, err := m.secst.RunPoSt(ctx, sset, r) + var faults []uint64 + proof, err := m.secst.RunPoSt(ctx, sset, r, faults) if err != nil { ret <- xerrors.Errorf("running post failed: %w", err) return diff --git a/storage/sector/store.go b/storage/sector/store.go index cbad8917c..d83580a62 100644 --- a/storage/sector/store.go +++ b/storage/sector/store.go @@ -163,8 +163,8 @@ func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.Sect return s.sb.SealStatus(sector) } -func (s *Store) RunPoSt(ctx context.Context, sectors []*api.SectorInfo, r []byte) ([]byte, error) { - panic("NYI") +func (s *Store) RunPoSt(ctx context.Context, sectors []*api.SectorInfo, r []byte, faults []uint64) ([]byte, error) { + panic("TODO") } func (s *Store) Stop() { From fe7efa753d7da4f5d8ef7b352cf6d1e3496720f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 18 Sep 2019 13:01:52 +0200 Subject: [PATCH 08/23] events: Build on chain API calls --- api/api.go | 5 +- api/struct.go | 4 +- chain/events/events.go | 101 ++++++++++++++++++++++++++++++---- chain/events/events_called.go | 10 ++-- chain/events/events_height.go | 2 +- chain/events/events_test.go | 51 +++++++++++------ chain/store/store.go | 66 +++++++++++----------- chain/sync_test.go | 8 ++- node/impl/full/chain.go | 2 +- storage/miner.go | 46 ++++++++-------- 10 files changed, 200 insertions(+), 95 deletions(-) diff --git a/api/api.go b/api/api.go index a924379b2..950dc5fa2 100644 --- a/api/api.go +++ b/api/api.go @@ -44,7 +44,10 @@ type FullNode interface { Common // chain - ChainNotify(context.Context) (<-chan *store.HeadChange, error) + + // ChainNotify returns channel with chain head updates + // First message is guaranteed to be of len == 1, and type == 'current' + ChainNotify(context.Context) (<-chan []*store.HeadChange, error) ChainHead(context.Context) (*types.TipSet, error) // TODO: check serialization ChainSubmitBlock(ctx context.Context, blk *types.BlockMsg) error // TODO: check serialization ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) diff --git a/api/struct.go b/api/struct.go index 0a1c6f4d5..9c73f08da 100644 --- a/api/struct.go +++ b/api/struct.go @@ -38,7 +38,7 @@ type FullNodeStruct struct { CommonStruct Internal struct { - ChainNotify func(context.Context) (<-chan *store.HeadChange, error) `perm:"read"` + ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"` ChainSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"` ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"` ChainGetRandomness func(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) `perm:"read"` @@ -279,7 +279,7 @@ func (c *FullNodeStruct) ChainGetBlockReceipts(ctx context.Context, b cid.Cid) ( return c.Internal.ChainGetBlockReceipts(ctx, b) } -func (c *FullNodeStruct) ChainNotify(ctx context.Context) (<-chan *store.HeadChange, error) { +func (c *FullNodeStruct) ChainNotify(ctx context.Context) (<-chan []*store.HeadChange, error) { return c.Internal.ChainNotify(ctx) } diff --git a/chain/events/events.go b/chain/events/events.go index f333de9d1..1106c8096 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -1,12 +1,17 @@ package events import ( + "context" "sync" + "time" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" "golang.org/x/xerrors" + "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/build" + "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" ) @@ -23,30 +28,31 @@ type heightHandler struct { revert RevertHandler } -type eventChainStore interface { - SubscribeHeadChanges(f func(rev, app []*types.TipSet) error) - - GetHeaviestTipSet() *types.TipSet - MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) +type eventApi interface { + ChainNotify(context.Context) (<-chan []*store.HeadChange, error) + ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) } type Events struct { - cs eventChainStore + api eventApi tsc *tipSetCache lk sync.Mutex + ready sync.WaitGroup + readyOnce sync.Once + heightEvents calledEvents } -func NewEvents(cs eventChainStore) *Events { +func NewEvents(api eventApi) *Events { gcConfidence := 2 * build.ForkLengthThreshold tsc := newTSCache(gcConfidence) e := &Events{ - cs: cs, + api: api, tsc: tsc, @@ -60,7 +66,7 @@ func NewEvents(cs eventChainStore) *Events { }, calledEvents: calledEvents{ - cs: cs, + cs: api, tsc: tsc, gcConfidence: uint64(gcConfidence), @@ -72,14 +78,87 @@ func NewEvents(cs eventChainStore) *Events { }, } - _ = e.tsc.add(cs.GetHeaviestTipSet()) - cs.SubscribeHeadChanges(e.headChange) + e.ready.Add(1) + + go e.listenHeadChanges(context.TODO()) + + e.ready.Wait() // TODO: cleanup/gc goroutine return e } +func (e *Events) restartHeadChanges(ctx context.Context) { + go func() { + if ctx.Err() != nil { + log.Warnf("not restarting listenHeadChanges: context error: %s", ctx.Err()) + return + } + time.Sleep(time.Second) + log.Info("restarting listenHeadChanges") + e.listenHeadChanges(ctx) + }() +} + +func (e *Events) listenHeadChanges(ctx context.Context) { + notifs, err := e.api.ChainNotify(ctx) + if err != nil { + // TODO: retry + log.Errorf("listenHeadChanges ChainNotify call failed: %s", err) + e.restartHeadChanges(ctx) + return + } + + cur, ok := <-notifs // TODO: timeout? + if !ok { + log.Error("notification channel closed") + e.restartHeadChanges(ctx) + return + } + + if len(cur) != 1 { + log.Errorf("unexpected initial head notification length: %d", len(cur)) + e.restartHeadChanges(ctx) + return + } + + if cur[0].Type != store.HCCurrent { + log.Errorf("expected first head notification type to be 'current', was '%s'", cur[0].Type) + e.restartHeadChanges(ctx) + return + } + + if err := e.tsc.add(cur[0].Val); err != nil { + log.Warn("tsc.add: adding current tipset failed: %s", err) + } + + e.readyOnce.Do(func() { + e.ready.Done() + }) + + for notif := range notifs { + var rev, app []*types.TipSet + for _, notif := range notif { + switch notif.Type { + case store.HCRevert: + rev = append(rev, notif.Val) + case store.HCApply: + app = append(app, notif.Val) + default: + log.Warnf("unexpected head change notification type: '%s'", notif.Type) + } + } + + if err := e.headChange(rev, app); err != nil { + log.Warnf("headChange failed: %s", err) + } + } + + log.Warn("listenHeadChanges loop quit") + e.restartHeadChanges(ctx) +} + func (e *Events) headChange(rev, app []*types.TipSet) error { if len(app) == 0 { return xerrors.New("events.headChange expected at least one applied tipset") diff --git a/chain/events/events_called.go b/chain/events/events_called.go index f4789c6e1..533c6cfd2 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -1,6 +1,7 @@ package events import ( + "context" "math" "sync" @@ -53,7 +54,7 @@ type queuedEvent struct { } type calledEvents struct { - cs eventChainStore + cs eventApi tsc *tipSetCache gcConfidence uint64 @@ -235,14 +236,15 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa seen := map[cid.Cid]struct{}{} for _, tsb := range ts.Blocks() { - bmsgs, smsgs, err := e.cs.MessagesForBlock(tsb) + + msgs, err := e.cs.ChainGetBlockMessages(context.TODO(), tsb.Messages) if err != nil { log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err) // this is quite bad, but probably better than missing all the other updates continue } - for _, m := range bmsgs { + for _, m := range msgs.BlsMessages { _, ok := seen[m.Cid()] if ok { continue @@ -252,7 +254,7 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa consume(m) } - for _, m := range smsgs { + for _, m := range msgs.SecpkMessages { _, ok := seen[m.Message.Cid()] if ok { continue diff --git a/chain/events/events_height.go b/chain/events/events_height.go index 8f12f626d..0826e6fc2 100644 --- a/chain/events/events_height.go +++ b/chain/events/events_height.go @@ -23,7 +23,7 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error { e.lk.Lock() defer e.lk.Unlock() - // highest tipset is always the first (see cs.ReorgOps) + // highest tipset is always the first (see api.ReorgOps) newH := app[0].Height() for _, ts := range rev { diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 37a1d653a..45ba41488 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -1,8 +1,12 @@ package events import ( + "context" "fmt" + "github.com/filecoin-project/go-lotus/api" + "github.com/filecoin-project/go-lotus/chain/store" "testing" + "time" "github.com/ipfs/go-cid" "github.com/multiformats/go-multihash" @@ -31,7 +35,7 @@ type fakeCS struct { msgs map[cid.Cid]fakeMsg - sub func(rev, app []*types.TipSet) error + sub func(rev, app []*types.TipSet) } func makeTs(t *testing.T, h uint64, msgcid cid.Cid) *types.TipSet { @@ -50,24 +54,39 @@ func makeTs(t *testing.T, h uint64, msgcid cid.Cid) *types.TipSet { return ts } -func (fcs *fakeCS) SubscribeHeadChanges(f func(rev, app []*types.TipSet) error) { - if fcs.sub != nil { - fcs.t.Fatal("sub should be nil") +func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*store.HeadChange, error) { + out := make(chan []*store.HeadChange, 1) + out <- []*store.HeadChange{{Type: store.HCCurrent, Val: fcs.tsc.best()}} + + fcs.sub = func(rev, app []*types.TipSet) { + notif := make([]*store.HeadChange, len(rev)+len(app)) + + for i, r := range rev { + notif[i] = &store.HeadChange{ + Type: store.HCRevert, + Val: r, + } + } + for i, r := range app { + notif[i+len(rev)] = &store.HeadChange{ + Type: store.HCApply, + Val: r, + } + } + + out <- notif } - fcs.sub = f + + return out, nil } -func (fcs *fakeCS) GetHeaviestTipSet() *types.TipSet { - return fcs.tsc.best() -} - -func (fcs *fakeCS) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) { - ms, ok := fcs.msgs[b.Messages] +func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, messages cid.Cid) (*api.BlockMessages, error) { + ms, ok := fcs.msgs[messages] if ok { - return ms.bmsgs, ms.smsgs, nil + return &api.BlockMessages{BlsMessages: ms.bmsgs, SecpkMessages: ms.smsgs}, nil } - return []*types.Message{}, []*types.SignedMessage{}, nil + return &api.BlockMessages{}, nil } func (fcs *fakeCS) fakeMsgs(m fakeMsg) cid.Cid { @@ -113,11 +132,11 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid) { // todo: allow apps[app-i-1] = ts } - err := fcs.sub(revs, apps) - require.NoError(fcs.t, err) + fcs.sub(revs, apps) + time.Sleep(100 * time.Millisecond) // TODO: :c } -var _ eventChainStore = &fakeCS{} +var _ eventApi = &fakeCS{} func TestAt(t *testing.T) { fcs := &fakeCS{ diff --git a/chain/store/store.go b/chain/store/store.go index 43c39991d..85b846521 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -54,18 +54,23 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore { hcnf := func(rev, app []*types.TipSet) error { cs.pubLk.Lock() defer cs.pubLk.Unlock() - for _, r := range rev { - cs.bestTips.Pub(&HeadChange{ + + notif := make([]*HeadChange, len(rev)+len(app)) + + for i, r := range rev { + notif[i] = &HeadChange{ Type: HCRevert, Val: r, - }, "headchange") + } } - for _, r := range app { - cs.bestTips.Pub(&HeadChange{ + for i, r := range app { + notif[i+len(rev)] = &HeadChange{ Type: HCApply, Val: r, - }, "headchange") + } } + + cs.bestTips.Pub(notif, "headchange") return nil } @@ -112,18 +117,6 @@ func (cs *ChainStore) writeHead(ts *types.TipSet) error { return nil } -func (cs *ChainStore) SubNewTips() chan *types.TipSet { - subch := cs.bestTips.Sub("best") - out := make(chan *types.TipSet) - go func() { - defer close(out) - for val := range subch { - out <- val.(*types.TipSet) - } - }() - return out -} - const ( HCRevert = "revert" HCApply = "apply" @@ -135,17 +128,17 @@ type HeadChange struct { Val *types.TipSet } -func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan *HeadChange { +func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan []*HeadChange { cs.pubLk.Lock() subch := cs.bestTips.Sub("headchange") head := cs.GetHeaviestTipSet() cs.pubLk.Unlock() - out := make(chan *HeadChange, 16) - out <- &HeadChange{ + out := make(chan []*HeadChange, 16) + out <- []*HeadChange{{ Type: HCCurrent, Val: head, - } + }} go func() { defer close(out) @@ -156,8 +149,11 @@ func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan *HeadChange { log.Warn("chain head sub exit loop") return } + if len(out) > 0 { + log.Warnf("head change sub is slow, has %d buffered entries", len(out)) + } select { - case out <- val.(*HeadChange): + case out <- val.([]*HeadChange): case <-ctx.Done(): } case <-ctx.Done(): @@ -610,20 +606,22 @@ func (cs *ChainStore) WaitForMessage(ctx context.Context, mcid cid.Cid) (cid.Cid for { select { - case val, ok := <-tsub: + case notif, ok := <-tsub: if !ok { return cid.Undef, nil, ctx.Err() } - switch val.Type { - case HCRevert: - continue - case HCApply: - bc, r, err := cs.tipsetContainsMsg(val.Val, mcid) - if err != nil { - return cid.Undef, nil, err - } - if r != nil { - return bc, r, nil + for _, val := range notif { + switch val.Type { + case HCRevert: + continue + case HCApply: + bc, r, err := cs.tipsetContainsMsg(val.Val, mcid) + if err != nil { + return cid.Undef, nil, err + } + if r != nil { + return bc, r, nil + } } } case <-ctx.Done(): diff --git a/chain/sync_test.go b/chain/sync_test.go index 56f98cc7d..47b8f4ec3 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -223,9 +223,11 @@ func (tu *syncTestUtil) waitUntilSync(from, to int) { } // TODO: some sort of timeout? - for c := range hc { - if c.Val.Equals(target) { - return + for n := range hc { + for _, c := range n { + if c.Val.Equals(target) { + return + } } } } diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 2e429dde0..683ba73d7 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -22,7 +22,7 @@ type ChainAPI struct { PubSub *pubsub.PubSub } -func (a *ChainAPI) ChainNotify(ctx context.Context) (<-chan *store.HeadChange, error) { +func (a *ChainAPI) ChainNotify(ctx context.Context) (<-chan []*store.HeadChange, error) { return a.Chain.SubHeadChanges(ctx), nil } diff --git a/storage/miner.go b/storage/miner.go index 2d3278c9f..71aa77b88 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -52,7 +52,7 @@ type storageMinerApi interface { MpoolGetNonce(context.Context, address.Address) (uint64, error) ChainWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) - ChainNotify(context.Context) (<-chan *store.HeadChange, error) + ChainNotify(context.Context) (<-chan []*store.HeadChange, error) ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) @@ -184,14 +184,14 @@ func (m *Miner) runPoSt(ctx context.Context) { } curhead := <-notifs - if curhead.Type != store.HCCurrent { + if curhead[0].Type != store.HCCurrent { // TODO: this is probably 'crash the node' level serious log.Warning("expected to get current best tipset from chain notifications stream") return } postCtx, cancel := context.WithCancel(ctx) - postWaitCh, onBlock, err := m.maybeDoPost(postCtx, curhead.Val) + postWaitCh, onBlock, err := m.maybeDoPost(postCtx, curhead[0].Val) if err != nil { log.Errorf("initial 'maybeDoPost' call failed: %s", err) return @@ -200,29 +200,31 @@ func (m *Miner) runPoSt(ctx context.Context) { for { select { case <-ctx.Done(): - case ch, ok := <-notifs: - if !ok { - log.Warning("chain notifications stream terminated") - // TODO: attempt to restart it if the context isnt cancelled - return - } - - switch ch.Type { - case store.HCApply: - postWaitCh, onBlock, err = m.maybeDoPost(postCtx, ch.Val) - if err != nil { - log.Errorf("maybeDoPost failed: %s", err) + case notif, ok := <-notifs: + for _, ch := range notif { + if !ok { + log.Warning("chain notifications stream terminated") + // TODO: attempt to restart it if the context isnt cancelled return } - case store.HCRevert: - if onBlock != nil { - if ch.Val.Contains(onBlock.Cid()) { - // Our post may now be invalid! - cancel() // probably the right thing to do? + + switch ch.Type { + case store.HCApply: + postWaitCh, onBlock, err = m.maybeDoPost(postCtx, ch.Val) + if err != nil { + log.Errorf("maybeDoPost failed: %s", err) + return } + case store.HCRevert: + if onBlock != nil { + if ch.Val.Contains(onBlock.Cid()) { + // Our post may now be invalid! + cancel() // probably the right thing to do? + } + } + case store.HCCurrent: + log.Warn("got 'current' chain notification in middle of stream") } - case store.HCCurrent: - log.Warn("got 'current' chain notification in middle of stream") } case perr := <-postWaitCh: if perr != nil { From b85937dcdfa90eb23cb6af8ac546abfefa7ed115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 18 Sep 2019 13:10:23 +0200 Subject: [PATCH 09/23] events: More test cases for ChainAt --- chain/events/events_test.go | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 45ba41488..1fb751abf 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -197,6 +197,70 @@ func TestAt(t *testing.T) { require.Equal(t, false, reverted) } +func TestAtStart(t *testing.T) { + fcs := &fakeCS{ + t: t, + h: 1, + tsc: newTSCache(2 * build.ForkLengthThreshold), + } + require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) + + events := NewEvents(fcs) + + fcs.advance(0, 5, nil) // 6 + + var applied bool + var reverted bool + + err := events.ChainAt(func(ts *types.TipSet, curH uint64) error { + require.Equal(t, 5, int(ts.Height())) + require.Equal(t, 8, int(curH)) + applied = true + return nil + }, func(ts *types.TipSet) error { + reverted = true + return nil + }, 3, 5) + require.NoError(t, err) + + require.Equal(t, false, applied) + require.Equal(t, false, reverted) + + fcs.advance(0, 5, nil) // 11 + require.Equal(t, true, applied) + require.Equal(t, false, reverted) +} + +func TestAtStartConfidence(t *testing.T) { + fcs := &fakeCS{ + t: t, + h: 1, + tsc: newTSCache(2 * build.ForkLengthThreshold), + } + require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) + + events := NewEvents(fcs) + + fcs.advance(0, 10, nil) // 11 + + var applied bool + var reverted bool + + err := events.ChainAt(func(ts *types.TipSet, curH uint64) error { + require.Equal(t, 5, int(ts.Height())) + require.Equal(t, 11, int(curH)) + applied = true + return nil + }, func(ts *types.TipSet) error { + reverted = true + return nil + }, 3, 5) + require.NoError(t, err) + + require.Equal(t, true, applied) + require.Equal(t, false, reverted) +} + func TestCalled(t *testing.T) { fcs := &fakeCS{ t: t, From 76ce3d9bb2b0bfcacd8ba81225308af982b9b347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 18 Sep 2019 13:45:52 +0200 Subject: [PATCH 10/23] events: Call ChainGetBlockMessages with the right CID --- chain/events/events_called.go | 2 +- chain/events/events_test.go | 46 +++++++++++++++++++++++------------ storage/miner.go | 9 +++++-- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/chain/events/events_called.go b/chain/events/events_called.go index 533c6cfd2..3caab9f17 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -237,7 +237,7 @@ func (e *calledEvents) messagesForTs(ts *types.TipSet, consume func(*types.Messa for _, tsb := range ts.Blocks() { - msgs, err := e.cs.ChainGetBlockMessages(context.TODO(), tsb.Messages) + msgs, err := e.cs.ChainGetBlockMessages(context.TODO(), tsb.Cid()) if err != nil { log.Errorf("messagesForTs MessagesForBlock failed (ts.H=%d, Bcid:%s, B.Mcid:%s): %s", ts.Height(), tsb.Cid(), tsb.Messages, err) // this is quite bad, but probably better than missing all the other updates diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 1fb751abf..4b7eabaf5 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -33,7 +33,8 @@ type fakeCS struct { h uint64 tsc *tipSetCache - msgs map[cid.Cid]fakeMsg + msgs map[cid.Cid]fakeMsg + blkMsgs map[cid.Cid]cid.Cid sub func(rev, app []*types.TipSet) } @@ -80,13 +81,18 @@ func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*store.HeadChange, err return out, nil } -func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, messages cid.Cid) (*api.BlockMessages, error) { - ms, ok := fcs.msgs[messages] - if ok { - return &api.BlockMessages{BlsMessages: ms.bmsgs, SecpkMessages: ms.smsgs}, nil +func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, blk cid.Cid) (*api.BlockMessages, error) { + messages, ok := fcs.blkMsgs[blk] + if !ok { + return &api.BlockMessages{}, nil } - return &api.BlockMessages{}, nil + ms, ok := fcs.msgs[messages] + if !ok { + return &api.BlockMessages{}, nil + } + return &api.BlockMessages{BlsMessages: ms.bmsgs, SecpkMessages: ms.smsgs}, nil + } func (fcs *fakeCS) fakeMsgs(m fakeMsg) cid.Cid { @@ -121,14 +127,18 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid) { // todo: allow for i := 0; i < app; i++ { fcs.h++ - mc, _ := msgs[i] - if mc == cid.Undef { + mc, hasMsgs := msgs[i] + if !hasMsgs { mc = dummyCid } ts := makeTs(fcs.t, fcs.h, mc) require.NoError(fcs.t, fcs.tsc.add(ts)) + if hasMsgs { + fcs.blkMsgs[ts.Blocks()[0].Cid()] = mc + } + apps[app-i-1] = ts } @@ -266,8 +276,9 @@ func TestCalled(t *testing.T) { t: t, h: 1, - msgs: map[cid.Cid]fakeMsg{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + msgs: map[cid.Cid]fakeMsg{}, + blkMsgs: map[cid.Cid]cid.Cid{}, + tsc: newTSCache(2 * build.ForkLengthThreshold), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -463,8 +474,9 @@ func TestCalledTimeout(t *testing.T) { t: t, h: 1, - msgs: map[cid.Cid]fakeMsg{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + msgs: map[cid.Cid]fakeMsg{}, + blkMsgs: map[cid.Cid]cid.Cid{}, + tsc: newTSCache(2 * build.ForkLengthThreshold), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -502,8 +514,9 @@ func TestCalledTimeout(t *testing.T) { t: t, h: 1, - msgs: map[cid.Cid]fakeMsg{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + msgs: map[cid.Cid]fakeMsg{}, + blkMsgs: map[cid.Cid]cid.Cid{}, + tsc: newTSCache(2 * build.ForkLengthThreshold), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -535,8 +548,9 @@ func TestCalledOrder(t *testing.T) { t: t, h: 1, - msgs: map[cid.Cid]fakeMsg{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + msgs: map[cid.Cid]fakeMsg{}, + blkMsgs: map[cid.Cid]cid.Cid{}, + tsc: newTSCache(2 * build.ForkLengthThreshold), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) diff --git a/storage/miner.go b/storage/miner.go index 71aa77b88..5ae6b3663 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -14,6 +14,7 @@ import ( "github.com/filecoin-project/go-lotus/build" "github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/address" + "github.com/filecoin-project/go-lotus/chain/events" "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/lib/sectorbuilder" @@ -24,7 +25,8 @@ import ( var log = logging.Logger("storageminer") type Miner struct { - api storageMinerApi + api storageMinerApi + events *events.Events secst *sector.Store commt *commitment.Tracker @@ -55,6 +57,7 @@ type storageMinerApi interface { ChainNotify(context.Context) (<-chan []*store.HeadChange, error) ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) + ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) WalletBalance(context.Context, address.Address) (types.BigInt, error) WalletSign(context.Context, address.Address, []byte) (*types.Signature, error) @@ -63,7 +66,9 @@ type storageMinerApi interface { func NewMiner(api storageMinerApi, addr address.Address, h host.Host, ds datastore.Batching, secst *sector.Store, commt *commitment.Tracker) (*Miner, error) { return &Miner{ - api: api, + api: api, + events: events.NewEvents(api), + maddr: addr, h: h, ds: ds, From cc82cc9675d0ba9ef4a9bcb9a706b8872b2b64b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 18 Sep 2019 15:32:21 +0200 Subject: [PATCH 11/23] miner: Initial event system integration --- chain/events/events.go | 3 +- chain/events/events_test.go | 18 ++++--- chain/events/tscache.go | 13 +++-- node/impl/full/chain.go | 2 +- storage/miner.go | 100 +++++++++++++++++------------------- 5 files changed, 69 insertions(+), 67 deletions(-) diff --git a/chain/events/events.go b/chain/events/events.go index 1106c8096..3fdad1cb3 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -31,6 +31,7 @@ type heightHandler struct { type eventApi interface { ChainNotify(context.Context) (<-chan []*store.HeadChange, error) ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) + ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) } type Events struct { @@ -49,7 +50,7 @@ type Events struct { func NewEvents(api eventApi) *Events { gcConfidence := 2 * build.ForkLengthThreshold - tsc := newTSCache(gcConfidence) + tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight) e := &Events{ api: api, diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 4b7eabaf5..2d61edf35 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -39,6 +39,10 @@ type fakeCS struct { sub func(rev, app []*types.TipSet) } +func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) { + panic("Not Implemented") +} + func makeTs(t *testing.T, h uint64, msgcid cid.Cid) *types.TipSet { ts, err := types.NewTipSet([]*types.BlockHeader{ { @@ -152,7 +156,7 @@ func TestAt(t *testing.T) { fcs := &fakeCS{ t: t, h: 1, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -211,7 +215,7 @@ func TestAtStart(t *testing.T) { fcs := &fakeCS{ t: t, h: 1, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -245,7 +249,7 @@ func TestAtStartConfidence(t *testing.T) { fcs := &fakeCS{ t: t, h: 1, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -278,7 +282,7 @@ func TestCalled(t *testing.T) { msgs: map[cid.Cid]fakeMsg{}, blkMsgs: map[cid.Cid]cid.Cid{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -476,7 +480,7 @@ func TestCalledTimeout(t *testing.T) { msgs: map[cid.Cid]fakeMsg{}, blkMsgs: map[cid.Cid]cid.Cid{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -516,7 +520,7 @@ func TestCalledTimeout(t *testing.T) { msgs: map[cid.Cid]fakeMsg{}, blkMsgs: map[cid.Cid]cid.Cid{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) @@ -550,7 +554,7 @@ func TestCalledOrder(t *testing.T) { msgs: map[cid.Cid]fakeMsg{}, blkMsgs: map[cid.Cid]cid.Cid{}, - tsc: newTSCache(2 * build.ForkLengthThreshold), + tsc: newTSCache(2*build.ForkLengthThreshold, nil), } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) diff --git a/chain/events/tscache.go b/chain/events/tscache.go index 630aed0d0..33493a4b8 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -1,24 +1,31 @@ package events import ( + "context" "golang.org/x/xerrors" "github.com/filecoin-project/go-lotus/chain/types" ) +type tsByHFunc func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) + // tipSetCache implements a simple ring-buffer cache to keep track of recent // tipsets type tipSetCache struct { cache []*types.TipSet start int len int + + storage tsByHFunc } -func newTSCache(cap int) *tipSetCache { +func newTSCache(cap int, storage tsByHFunc) *tipSetCache { return &tipSetCache{ cache: make([]*types.TipSet, cap), start: 0, len: 0, + + storage: storage, } } @@ -66,9 +73,7 @@ func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) { tailH := tsc.cache[(tsc.start-tsc.len+1)%len(tsc.cache)].Height() if height < tailH { - // TODO: we can try to walk parents, but that shouldn't happen in - // practice, so it's probably not worth implementing - return nil, xerrors.Errorf("tipSetCache.get: requested tipset not in cache (req: %d, cache tail: %d)", height, tailH) + return tsc.storage(context.TODO(), height, tsc.cache[tailH]) } return tsc.cache[int(height-tailH+1)%len(tsc.cache)], nil diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 683ba73d7..94fb5717e 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -109,5 +109,5 @@ func (a *ChainAPI) ChainGetBlockReceipts(ctx context.Context, bcid cid.Cid) ([]* } func (a *ChainAPI) ChainGetTipSetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) { - panic("NYI") + return a.Chain.GetTipsetByHeight(ctx, h, ts) } diff --git a/storage/miner.go b/storage/miner.go index 5ae6b3663..5cbb7015d 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -2,11 +2,10 @@ package storage import ( "context" - "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log" - host "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/host" "github.com/pkg/errors" "golang.org/x/xerrors" @@ -24,6 +23,8 @@ import ( var log = logging.Logger("storageminer") +const PoStConfidence = 0 + type Miner struct { api storageMinerApi events *events.Events @@ -53,6 +54,7 @@ type storageMinerApi interface { MpoolPush(context.Context, *types.SignedMessage) error MpoolGetNonce(context.Context, address.Address) (uint64, error) + ChainHead(context.Context) (*types.TipSet, error) ChainWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) ChainNotify(context.Context) (<-chan []*store.HeadChange, error) ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) @@ -82,8 +84,13 @@ func (m *Miner) Run(ctx context.Context) error { return errors.Wrap(err, "miner preflight checks failed") } + ts, err := m.api.ChainHead(ctx) + if err != nil { + return err + } + go m.handlePostingSealedSectors(ctx) - go m.runPoSt(ctx) + go m.schedulePoSt(ctx, ts) return nil } @@ -179,70 +186,54 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal return nil } -func (m *Miner) runPoSt(ctx context.Context) { - // TODO: most of this method can probably be replaced by the events module once it works on top of the api - notifs, err := m.api.ChainNotify(ctx) +func (m *Miner) schedulePoSt(ctx context.Context, baseTs *types.TipSet) { + ppe, err := m.api.StateMinerProvingPeriodEnd(ctx, m.maddr, baseTs) if err != nil { - // TODO: this is probably 'crash the node' level serious - log.Errorf("POST ROUTINE FAILED: failed to get chain notifications stream: %s", err) + log.Errorf("failed to get proving period end for miner: %s", err) return } - curhead := <-notifs - if curhead[0].Type != store.HCCurrent { - // TODO: this is probably 'crash the node' level serious - log.Warning("expected to get current best tipset from chain notifications stream") + if ppe == 0 { + log.Errorf("Proving period end == 0") + // TODO: we probably want to call schedulePoSt after the first commitSector call return } - postCtx, cancel := context.WithCancel(ctx) - postWaitCh, onBlock, err := m.maybeDoPost(postCtx, curhead[0].Val) + log.Infof("Scheduling post at height %d", ppe) + // TODO: Should we set confidence to randomness lookback? + err = m.events.ChainAt(m.startPost, func(ts *types.TipSet) error { // Revert + // TODO: Cancel post + return nil + }, PoStConfidence, ppe) if err != nil { - log.Errorf("initial 'maybeDoPost' call failed: %s", err) + // TODO: This is BAD, figure something out + log.Errorf("scheduling PoSt failed: %s", err) return } +} - for { - select { - case <-ctx.Done(): - case notif, ok := <-notifs: - for _, ch := range notif { - if !ok { - log.Warning("chain notifications stream terminated") - // TODO: attempt to restart it if the context isnt cancelled - return - } +func (m *Miner) startPost(ts *types.TipSet, curH uint64) error { + postWaitCh, _, err := m.maybeDoPost(context.TODO(), ts) + if err != nil { + return err + } - switch ch.Type { - case store.HCApply: - postWaitCh, onBlock, err = m.maybeDoPost(postCtx, ch.Val) - if err != nil { - log.Errorf("maybeDoPost failed: %s", err) - return - } - case store.HCRevert: - if onBlock != nil { - if ch.Val.Contains(onBlock.Cid()) { - // Our post may now be invalid! - cancel() // probably the right thing to do? - } - } - case store.HCCurrent: - log.Warn("got 'current' chain notification in middle of stream") - } - } - case perr := <-postWaitCh: - if perr != nil { - log.Errorf("got error back from postWaitCh: %s", err) - // TODO: what do we even do here? - return - } - postWaitCh = nil - onBlock = nil - // yay? - log.Infof("post successfully submitted") + if postWaitCh == nil { + return errors.New("PoSt didn't start") + } + + go func() { + err := <-postWaitCh + if err != nil { + log.Errorf("got error back from postWaitCh: %s", err) + return } - } + + log.Infof("post successfully submitted") + + m.schedulePoSt(context.TODO(), ts) + }() + return nil } func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error, *types.BlockHeader, error) { @@ -252,6 +243,7 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error } if ppe < ts.Height() { + log.Warnf("skipping post, supplied tipset too high: ppe=%d, ts.H=%d", ppe, ts.Height()) return nil, nil, nil } From 689b1e5b3cc5a3060f4c0ee862adb777dda0dc13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 18 Sep 2019 20:07:39 +0200 Subject: [PATCH 12/23] events: Safer restarting in listenHeadChanges --- chain/events/events.go | 39 ++++++++++++++++--------------------- chain/events/events_test.go | 14 ++++++------- storage/miner.go | 5 +++-- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/chain/events/events.go b/chain/events/events.go index 3fdad1cb3..c58ab4e81 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -47,7 +47,7 @@ type Events struct { calledEvents } -func NewEvents(api eventApi) *Events { +func NewEvents(ctx context.Context, api eventApi) *Events { gcConfidence := 2 * build.ForkLengthThreshold tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight) @@ -81,7 +81,7 @@ func NewEvents(api eventApi) *Events { e.ready.Add(1) - go e.listenHeadChanges(context.TODO()) + go e.listenHeadChanges(ctx) e.ready.Wait() @@ -90,48 +90,44 @@ func NewEvents(api eventApi) *Events { return e } -func (e *Events) restartHeadChanges(ctx context.Context) { - go func() { +func (e *Events) listenHeadChanges(ctx context.Context) { + for { + if err := e.listenHeadChangesOnce(ctx); err != nil { + log.Errorf("listen head changes errored: %s", err) + } else { + log.Warn("listenHeadChanges quit") + } if ctx.Err() != nil { log.Warnf("not restarting listenHeadChanges: context error: %s", ctx.Err()) return } time.Sleep(time.Second) log.Info("restarting listenHeadChanges") - e.listenHeadChanges(ctx) - }() + } } -func (e *Events) listenHeadChanges(ctx context.Context) { +func (e *Events) listenHeadChangesOnce(ctx context.Context) error { notifs, err := e.api.ChainNotify(ctx) if err != nil { // TODO: retry - log.Errorf("listenHeadChanges ChainNotify call failed: %s", err) - e.restartHeadChanges(ctx) - return + return xerrors.Errorf("listenHeadChanges ChainNotify call failed: %w", err) } cur, ok := <-notifs // TODO: timeout? if !ok { - log.Error("notification channel closed") - e.restartHeadChanges(ctx) - return + return xerrors.Errorf("notification channel closed") } if len(cur) != 1 { - log.Errorf("unexpected initial head notification length: %d", len(cur)) - e.restartHeadChanges(ctx) - return + return xerrors.Errorf("unexpected initial head notification length: %d", len(cur)) } if cur[0].Type != store.HCCurrent { - log.Errorf("expected first head notification type to be 'current', was '%s'", cur[0].Type) - e.restartHeadChanges(ctx) - return + return xerrors.Errorf("expected first head notification type to be 'current', was '%s'", cur[0].Type) } if err := e.tsc.add(cur[0].Val); err != nil { - log.Warn("tsc.add: adding current tipset failed: %s", err) + log.Warn("tsc.add: adding current tipset failed: %w", err) } e.readyOnce.Do(func() { @@ -156,8 +152,7 @@ func (e *Events) listenHeadChanges(ctx context.Context) { } } - log.Warn("listenHeadChanges loop quit") - e.restartHeadChanges(ctx) + return nil } func (e *Events) headChange(rev, app []*types.TipSet) error { diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 2d61edf35..4628b5fae 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -160,7 +160,7 @@ func TestAt(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events := NewEvents(fcs) + events := NewEvents(context.Background(), fcs) var applied bool var reverted bool @@ -219,7 +219,7 @@ func TestAtStart(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events := NewEvents(fcs) + events := NewEvents(context.Background(), fcs) fcs.advance(0, 5, nil) // 6 @@ -253,7 +253,7 @@ func TestAtStartConfidence(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events := NewEvents(fcs) + events := NewEvents(context.Background(), fcs) fcs.advance(0, 10, nil) // 11 @@ -286,7 +286,7 @@ func TestCalled(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events := NewEvents(fcs) + events := NewEvents(context.Background(), fcs) t0123, err := address.NewFromString("t0123") require.NoError(t, err) @@ -484,7 +484,7 @@ func TestCalledTimeout(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events := NewEvents(fcs) + events := NewEvents(context.Background(), fcs) t0123, err := address.NewFromString("t0123") require.NoError(t, err) @@ -524,7 +524,7 @@ func TestCalledTimeout(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events = NewEvents(fcs) + events = NewEvents(context.Background(), fcs) err = events.Called(func(ts *types.TipSet) (d bool, m bool, e error) { return true, true, nil @@ -558,7 +558,7 @@ func TestCalledOrder(t *testing.T) { } require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) - events := NewEvents(fcs) + events := NewEvents(context.Background(), fcs) t0123, err := address.NewFromString("t0123") require.NoError(t, err) diff --git a/storage/miner.go b/storage/miner.go index 5cbb7015d..2ffaa0c8b 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -68,8 +68,7 @@ type storageMinerApi interface { func NewMiner(api storageMinerApi, addr address.Address, h host.Host, ds datastore.Batching, secst *sector.Store, commt *commitment.Tracker) (*Miner, error) { return &Miner{ - api: api, - events: events.NewEvents(api), + api: api, maddr: addr, h: h, @@ -84,6 +83,8 @@ func (m *Miner) Run(ctx context.Context) error { return errors.Wrap(err, "miner preflight checks failed") } + m.events = events.NewEvents(ctx, m.api) + ts, err := m.api.ChainHead(ctx) if err != nil { return err From c40f89f2a9356359d5d2e1d2239f474621103b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 18:17:49 +0200 Subject: [PATCH 13/23] Almost working PoSt submission --- build/chain.go | 2 + build/params.go | 10 ++- chain/events/events_called.go | 3 - chain/events/events_height.go | 3 - chain/types/bitfield.go | 8 ++ lotuspond/front/src/StorageNode.js | 7 +- storage/miner.go | 113 ++++++++++++++++++++--------- storage/sector/store.go | 25 ++++++- 8 files changed, 123 insertions(+), 48 deletions(-) diff --git a/build/chain.go b/build/chain.go index b490aeedf..e01133310 100644 --- a/build/chain.go +++ b/build/chain.go @@ -1,5 +1,7 @@ package build +// Seconds const BlockDelay = 5 +// Seconds const AllowableClockDrift = BlockDelay * 2 diff --git a/build/params.go b/build/params.go index 28da4058c..00b4afe5c 100644 --- a/build/params.go +++ b/build/params.go @@ -7,14 +7,20 @@ const UnixfsLinksPerLevel = 1024 const SectorSize = 1024 +// Blocks const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours +// Blocks const DealVoucherSkewLimit = 10 +// Blocks const ForkLengthThreshold = 20 + +// Blocks const RandomnessLookback = 20 -const ProvingPeriodDuration = 2 * 60 // an hour, for now -const PoSTChallangeTime = 1 * 60 +// Blocks +const ProvingPeriodDuration = 20 +const PoSTChallangeTime = 10 // TODO: Move other important consts here diff --git a/chain/events/events_called.go b/chain/events/events_called.go index 3caab9f17..5b94010cf 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -82,9 +82,6 @@ type callTuple struct { } func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error { - e.lk.Lock() - defer e.lk.Unlock() - for _, ts := range rev { e.handleReverts(ts) } diff --git a/chain/events/events_height.go b/chain/events/events_height.go index 0826e6fc2..2fb3a4319 100644 --- a/chain/events/events_height.go +++ b/chain/events/events_height.go @@ -20,9 +20,6 @@ type heightEvents struct { } func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error { - e.lk.Lock() - defer e.lk.Unlock() - // highest tipset is always the first (see api.ReorgOps) newH := app[0].Height() diff --git a/chain/types/bitfield.go b/chain/types/bitfield.go index c59768ac1..347895f09 100644 --- a/chain/types/bitfield.go +++ b/chain/types/bitfield.go @@ -17,6 +17,14 @@ func NewBitField() BitField { return BitField{bits: make(map[uint64]struct{})} } +func BitFieldFromSet(setBits []uint64) BitField { + res := BitField{bits: make(map[uint64]struct{})} + for _, b := range setBits { + res.bits[b] = struct{}{} + } + return res +} + // Set ...s bit in the BitField func (bf BitField) Set(bit uint64) { bf.bits[bit] = struct{}{} diff --git a/lotuspond/front/src/StorageNode.js b/lotuspond/front/src/StorageNode.js index 2c813605c..ed7dcc66b 100644 --- a/lotuspond/front/src/StorageNode.js +++ b/lotuspond/front/src/StorageNode.js @@ -59,7 +59,6 @@ class StorageNode extends React.Component { // this.props.onConnect(client, id) // TODO: dedupe connecting part - this.loadInfo() let updates = setInterval(this.loadInfo, 1050) client.on('close', () => clearInterval(updates)) }) @@ -72,7 +71,10 @@ class StorageNode extends React.Component { const peers = await this.state.client.call("Filecoin.NetPeers", []) const [actor] = await this.state.client.call("Filecoin.ActorAddresses", []) - this.setState({version: version, peers: peers.length, actor: actor}) + const stActor = await this.props.fullConn.call('Filecoin.StateGetActor', [actor, null]) + const actorState = await this.props.fullConn.call('Filecoin.StateReadState', [stActor, null]) + + this.setState({version: version, peers: peers.length, actor: actor, actorState: actorState}) await this.stagedList() } @@ -109,6 +111,7 @@ class StorageNode extends React.Component {
+  PPE: {this.state.actorState.State.ProvingPeriodEnd}
{this.state.statusCounts.map((c, i) => {sealCodes[i]}: {c} | )}
diff --git a/storage/miner.go b/storage/miner.go index 2ffaa0c8b..ce84475d5 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -8,6 +8,7 @@ import ( "github.com/libp2p/go-libp2p-core/host" "github.com/pkg/errors" "golang.org/x/xerrors" + "sync" "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/build" @@ -23,7 +24,7 @@ import ( var log = logging.Logger("storageminer") -const PoStConfidence = 0 +const PoStConfidence = 1 type Miner struct { api storageMinerApi @@ -39,6 +40,9 @@ type Miner struct { h host.Host ds datastore.Batching + + schedLk sync.Mutex + postSched uint64 } type storageMinerApi interface { @@ -51,8 +55,7 @@ type storageMinerApi interface { StateMinerProvingPeriodEnd(context.Context, address.Address, *types.TipSet) (uint64, error) StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.SectorInfo, error) - MpoolPush(context.Context, *types.SignedMessage) error - MpoolGetNonce(context.Context, address.Address) (uint64, error) + MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) ChainHead(context.Context) (*types.TipSet, error) ChainWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) @@ -62,7 +65,6 @@ type storageMinerApi interface { ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) WalletBalance(context.Context, address.Address) (types.BigInt, error) - WalletSign(context.Context, address.Address, []byte) (*types.Signature, error) WalletHas(context.Context, address.Address) (bool, error) } @@ -144,7 +146,7 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal return errors.Wrap(aerr, "could not serialize commit sector parameters") } - msg := types.Message{ + msg := &types.Message{ To: m.maddr, From: m.worker, Method: actors.MAMethods.CommitSector, @@ -154,36 +156,24 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal GasPrice: types.NewInt(1), } - nonce, err := m.api.MpoolGetNonce(ctx, m.worker) + smsg, err := m.api.MpoolPushMessage(ctx, msg) if err != nil { - return errors.Wrap(err, "failed to get nonce") - } - - msg.Nonce = nonce - - data, err := msg.Serialize() - if err != nil { - return errors.Wrap(err, "serializing commit sector message") - } - - sig, err := m.api.WalletSign(ctx, m.worker, data) - if err != nil { - return errors.Wrap(err, "signing commit sector message") - } - - smsg := &types.SignedMessage{ - Message: msg, - Signature: *sig, - } - - if err := m.api.MpoolPush(ctx, smsg); err != nil { - return errors.Wrap(err, "pushing commit sector message to mpool") + return errors.Wrap(err, "pushing message to mpool") } if err := m.commt.TrackCommitSectorMsg(m.maddr, sinfo.SectorID, smsg.Cid()); err != nil { return errors.Wrap(err, "tracking sector commitment") } + go func() { + _, err := m.api.ChainWaitMsg(ctx, smsg.Cid()) + if err != nil { + return + } + + m.schedulePoSt(ctx, nil) + }() + return nil } @@ -200,12 +190,21 @@ func (m *Miner) schedulePoSt(ctx context.Context, baseTs *types.TipSet) { return } - log.Infof("Scheduling post at height %d", ppe) - // TODO: Should we set confidence to randomness lookback? + m.schedLk.Lock() + + if m.postSched >= ppe { + log.Warn("schedulePoSt already called for proving period >= %d", m.postSched) + m.schedLk.Unlock() + return + } + m.postSched = ppe + m.schedLk.Unlock() + + log.Infof("Scheduling post at height %d", ppe-build.PoSTChallangeTime) err = m.events.ChainAt(m.startPost, func(ts *types.TipSet) error { // Revert // TODO: Cancel post return nil - }, PoStConfidence, ppe) + }, PoStConfidence, ppe-build.PoSTChallangeTime) if err != nil { // TODO: This is BAD, figure something out log.Errorf("scheduling PoSt failed: %s", err) @@ -214,7 +213,14 @@ func (m *Miner) schedulePoSt(ctx context.Context, baseTs *types.TipSet) { } func (m *Miner) startPost(ts *types.TipSet, curH uint64) error { - postWaitCh, _, err := m.maybeDoPost(context.TODO(), ts) + log.Info("starting PoSt computation") + + head, err := m.api.ChainHead(context.TODO()) + if err != nil { + return err + } + + postWaitCh, _, err := m.maybeDoPost(context.TODO(), head) if err != nil { return err } @@ -253,18 +259,19 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return nil, nil, xerrors.Errorf("failed to get proving set for miner: %w", err) } - r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(ts.Height()-ppe)) + r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(ts.Height()-ppe+build.ProvingPeriodDuration)) // TODO: review: check math if err != nil { return nil, nil, xerrors.Errorf("failed to get chain randomness for post: %w", err) } - sourceTs, err := m.api.ChainGetTipSetByHeight(ctx, ppe, ts) + sourceTs, err := m.api.ChainGetTipSetByHeight(ctx, ppe-build.ProvingPeriodDuration, ts) if err != nil { return nil, nil, xerrors.Errorf("failed to get post start tipset: %w", err) } ret := make(chan error, 1) go func() { + log.Info("running PoSt computation") var faults []uint64 proof, err := m.secst.RunPoSt(ctx, sset, r, faults) if err != nil { @@ -272,8 +279,34 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return } - // TODO: submit post... - _ = proof + log.Info("submitting PoSt") + + params := &actors.SubmitPoStParams{ + Proof: proof, + DoneSet: types.BitFieldFromSet(sectorIdList(sset)), + } + + enc, aerr := actors.SerializeParams(params) + if aerr != nil { + ret <- xerrors.Errorf("could not serialize submit post parameters: %w", err) + return + } + + msg := &types.Message{ + To: m.maddr, + From: m.worker, + Method: actors.MAMethods.SubmitPoSt, + Params: enc, + Value: types.NewInt(0), + GasLimit: types.NewInt(100000 /* i dont know help */), + GasPrice: types.NewInt(1), + } + + _, err = m.api.MpoolPushMessage(ctx, msg) + if err != nil { + ret <- xerrors.Errorf("pushing message to mpool: %w", err) + return + } // make sure it succeeds... // m.api.ChainWaitMsg() @@ -283,6 +316,14 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return ret, sourceTs.MinTicketBlock(), nil } +func sectorIdList(si []*api.SectorInfo) []uint64 { + out := make([]uint64, len(si)) + for i, s := range si { + out[i] = s.SectorID + } + return out +} + func (m *Miner) runPreflightChecks(ctx context.Context) error { worker, err := m.api.StateMinerWorker(ctx, m.maddr, nil) if err != nil { diff --git a/storage/sector/store.go b/storage/sector/store.go index d83580a62..975688c8d 100644 --- a/storage/sector/store.go +++ b/storage/sector/store.go @@ -2,6 +2,7 @@ package sector import ( "context" + "golang.org/x/xerrors" "io" "io/ioutil" "os" @@ -41,7 +42,7 @@ func (s *Store) Service() { } func (s *Store) poll() { - log.Info("polling for sealed sectors...") + log.Debug("polling for sealed sectors...") // get a list of sectors to poll s.lk.Lock() @@ -164,7 +165,27 @@ func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.Sect } func (s *Store) RunPoSt(ctx context.Context, sectors []*api.SectorInfo, r []byte, faults []uint64) ([]byte, error) { - panic("TODO") + sbsi := make([]sectorbuilder.SectorInfo, len(sectors)) + for k, sector := range sectors { + var commR [sectorbuilder.CommLen]byte + if copy(commR[:], sector.CommR) != sectorbuilder.CommLen { + return nil, xerrors.Errorf("commR too short, %d bytes", len(sector.CommR)) + } + + sbsi[k] = sectorbuilder.SectorInfo{ + SectorID: sector.SectorID, + CommR: commR, + } + } + + ssi := sectorbuilder.NewSortedSectorInfo(sbsi) + + var seed [sectorbuilder.CommLen]byte + if copy(seed[:], r) != sectorbuilder.CommLen { + return nil, xerrors.Errorf("random seed too short, %d bytes", len(r)) + } + + return s.sb.GeneratePoSt(ssi, seed, faults) } func (s *Store) Stop() { From 839597012d27cc19d1aa420a9fd7de0ffa8c4163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 19:38:48 +0200 Subject: [PATCH 14/23] Fix post seed height math --- build/chain.go | 2 +- build/params.go | 4 ++-- chain/actors/actor_miner.go | 7 +++++++ chain/messagepool.go | 2 +- chain/store/store.go | 1 + chain/vm/vm.go | 6 ++++-- storage/miner.go | 9 +++++---- 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/build/chain.go b/build/chain.go index e01133310..ae00b8e55 100644 --- a/build/chain.go +++ b/build/chain.go @@ -1,7 +1,7 @@ package build // Seconds -const BlockDelay = 5 +const BlockDelay = 3 // Seconds const AllowableClockDrift = BlockDelay * 2 diff --git a/build/params.go b/build/params.go index 00b4afe5c..365fdc656 100644 --- a/build/params.go +++ b/build/params.go @@ -20,7 +20,7 @@ const ForkLengthThreshold = 20 const RandomnessLookback = 20 // Blocks -const ProvingPeriodDuration = 20 -const PoSTChallangeTime = 10 +const ProvingPeriodDuration = 10 +const PoSTChallangeTime = 5 // TODO: Move other important consts here diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index 02f6b5d08..cc4a4f2a2 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -2,6 +2,7 @@ package actors import ( "context" + "encoding/base64" "fmt" "github.com/filecoin-project/go-lotus/build" @@ -336,13 +337,16 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, } } + var dbgRandH uint64 var seed [sectorbuilder.CommLen]byte { var rand []byte var err ActorError if !lateSubmission { + dbgRandH = self.ProvingPeriodEnd - build.PoSTChallangeTime rand, err = vmctx.GetRandomness(self.ProvingPeriodEnd - build.PoSTChallangeTime) } else { + dbgRandH = nextProvingPeriodEnd - build.PoSTChallangeTime rand, err = vmctx.GetRandomness(nextProvingPeriodEnd - build.PoSTChallangeTime) } if err != nil { @@ -384,14 +388,17 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, faults := self.CurrentFaultSet.All() + log.Infof("VerifyPost; rh=%d r=%s pLen=%d", dbgRandH, base64.StdEncoding.EncodeToString(seed[:]), len(params.Proof)) if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize.Uint64(), sectorbuilder.NewSortedSectorInfo(sectorInfos), seed, params.Proof, faults); !ok || lerr != nil { if lerr != nil { // TODO: study PoST errors + log.Infof("Post Verify Error: %s", lerr) return nil, aerrors.Absorb(lerr, 4, "PoST error") } if !ok { + log.Info("post verification FAILED") return nil, aerrors.New(4, "PoST invalid") } } diff --git a/chain/messagepool.go b/chain/messagepool.go index 4ebde3512..0ce1db6f9 100644 --- a/chain/messagepool.go +++ b/chain/messagepool.go @@ -77,7 +77,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage) error { return err } - log.Info("mpooladd: %s", base64.StdEncoding.EncodeToString(data)) + log.Infof("mpooladd: %s", base64.StdEncoding.EncodeToString(data)) if err := m.Signature.Verify(m.Message.From, data); err != nil { return err diff --git a/chain/store/store.go b/chain/store/store.go index 85b846521..204b7de98 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -722,6 +722,7 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tick mtb := nts.MinTicketBlock() if nv < len(mtb.Tickets) { t := mtb.Tickets[len(mtb.Tickets)-(1+nv)] + log.Infof("Returning randomness: H:%d, t:%d, mtb:%s", nts.Height(), len(mtb.Tickets)-(1+nv), mtb.Cid()) return t.VDFResult, nil } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 9bf902d84..1666228b3 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -67,8 +67,10 @@ func (vmc *VMContext) Message() *types.Message { } func (vmc *VMContext) GetRandomness(height uint64) ([]byte, aerrors.ActorError) { - relHeight := int(vmc.BlockHeight()) - int(height) - res, err := vmc.vm.cs.GetRandomness(vmc.ctx, vmc.vm.cs.GetHeaviestTipSet(), nil, relHeight) + hts := vmc.vm.cs.GetHeaviestTipSet() + + relHeight := int(hts.Height() - height) + res, err := vmc.vm.cs.GetRandomness(vmc.ctx, hts, nil, relHeight) if err != nil { return nil, aerrors.Escalate(err, "could not get randomness") } diff --git a/storage/miner.go b/storage/miner.go index ce84475d5..1eb56bf2c 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -2,6 +2,7 @@ package storage import ( "context" + "encoding/base64" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log" @@ -259,19 +260,19 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return nil, nil, xerrors.Errorf("failed to get proving set for miner: %w", err) } - r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(ts.Height()-ppe+build.ProvingPeriodDuration)) // TODO: review: check math + r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(int64(ts.Height())-int64(ppe)+int64(build.PoSTChallangeTime))) // TODO: review: check math if err != nil { return nil, nil, xerrors.Errorf("failed to get chain randomness for post: %w", err) } - sourceTs, err := m.api.ChainGetTipSetByHeight(ctx, ppe-build.ProvingPeriodDuration, ts) + sourceTs, err := m.api.ChainGetTipSetByHeight(ctx, ppe-build.PoSTChallangeTime, ts) if err != nil { return nil, nil, xerrors.Errorf("failed to get post start tipset: %w", err) } ret := make(chan error, 1) go func() { - log.Info("running PoSt computation") + log.Infof("running PoSt computation, rh=%d r=%s, ppe=%d, h=%d", ts.Height()-(ts.Height()-ppe+build.PoSTChallangeTime), base64.StdEncoding.EncodeToString(r), ppe, ts.Height()) var faults []uint64 proof, err := m.secst.RunPoSt(ctx, sset, r, faults) if err != nil { @@ -279,7 +280,7 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return } - log.Info("submitting PoSt") + log.Infof("submitting PoSt pLen=%d", len(proof)) params := &actors.SubmitPoStParams{ Proof: proof, From 18b72b1584be20480fe1ea04bca6b886ca13cc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 20:15:14 +0200 Subject: [PATCH 15/23] Fix bigint serialization --- chain/actors/actor_miner.go | 8 ++++++- chain/actors/cbor_gen.go | 43 +++++++++++++++++++++++++++++++++++-- chain/types/bigint.go | 15 +++++++------ chain/types/cbor_gen.go | 27 +++++++++++++++++++---- 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index cc4a4f2a2..c624e47a7 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -294,7 +294,13 @@ type SubmitPoStParams struct { // TODO: this is a dummy method that allows us to plumb in other parts of the // system for now. -func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitPoStParams) ([]byte, ActorError) { +func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitPoStParams) (_ []byte, paerr ActorError) { + defer func() { + if paerr != nil { + log.Error(paerr) + } + }() + oldstate, self, err := loadState(vmctx) if err != nil { return nil, err diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index 381f22b7b..04d9fd163 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -759,7 +759,20 @@ func (t *SubmitPoStParams) MarshalCBOR(w io.Writer) error { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write([]byte{128}); err != nil { + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.t.Proof ([]uint8) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { + return err + } + if _, err := w.Write(t.Proof); err != nil { + return err + } + + // t.t.DoneSet (types.BitField) + if err := t.DoneSet.MarshalCBOR(w); err != nil { return err } return nil @@ -776,10 +789,36 @@ func (t *SubmitPoStParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 0 { + if extra != 2 { return fmt.Errorf("cbor input had wrong number of fields") } + // t.t.Proof ([]uint8) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("array too large") + } + + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Proof = make([]byte, extra) + if _, err := io.ReadFull(br, t.Proof); err != nil { + return err + } + // t.t.DoneSet (types.BitField) + + { + + if err := t.DoneSet.UnmarshalCBOR(br); err != nil { + return err + } + + } return nil } diff --git a/chain/types/bigint.go b/chain/types/bigint.go index 061cdf8a4..ed37930ff 100644 --- a/chain/types/bigint.go +++ b/chain/types/bigint.go @@ -107,13 +107,9 @@ func (bi *BigInt) MarshalCBOR(w io.Writer) error { return zero.MarshalCBOR(w) } - if bi.Sign() < 0 { - // right now we don't support negative integers. - // In the spec, everything is listed as a Uint. - return fmt.Errorf("BigInt does not support negative integers") - } + tag := uint64(^(bi.Sign()|1)+6) >> 1 - header := cbg.CborEncodeMajorType(cbg.MajTag, 2) + header := cbg.CborEncodeMajorType(cbg.MajTag, tag) if _, err := w.Write(header); err != nil { return err } @@ -138,10 +134,12 @@ func (bi *BigInt) UnmarshalCBOR(br io.Reader) error { return err } - if maj != cbg.MajTag && extra != 2 { + if maj != cbg.MajTag && extra != 2 && extra != 3 { return fmt.Errorf("cbor input for big int was not a tagged big int") } + minus := extra & 1 + maj, extra, err = cbg.CborReadHeader(br) if err != nil { return err @@ -161,6 +159,9 @@ func (bi *BigInt) UnmarshalCBOR(br io.Reader) error { } bi.Int = big.NewInt(0).SetBytes(buf) + if minus > 0 { + bi.Int.Neg(bi.Int) + } return nil } diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index a2df6b3ff..be91a35c7 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -1199,6 +1199,10 @@ func (t *MessageReceipt) UnmarshalCBOR(r io.Reader) error { } func (t *BlockMsg) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } if _, err := w.Write([]byte{131}); err != nil { return err } @@ -1230,7 +1234,8 @@ func (t *BlockMsg) MarshalCBOR(w io.Writer) error { return nil } -func (t *BlockMsg) UnmarshalCBOR(br io.Reader) error { +func (t *BlockMsg) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) maj, extra, err := cbg.CborReadHeader(br) if err != nil { @@ -1246,10 +1251,24 @@ func (t *BlockMsg) UnmarshalCBOR(br io.Reader) error { // t.t.Header (types.BlockHeader) - t.Header = new(BlockHeader) + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Header = new(BlockHeader) + if err := t.Header.UnmarshalCBOR(br); err != nil { + return err + } + } - if err := t.Header.UnmarshalCBOR(br); err != nil { - return err } // t.t.BlsMessages ([]cid.Cid) From 42b8af302fa18092f90e82adec6c080392d4b9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 20:31:25 +0200 Subject: [PATCH 16/23] get sector set size from AMT --- chain/actors/actor_miner.go | 21 +++++++++++---------- chain/actors/cbor_gen.go | 34 ++-------------------------------- 2 files changed, 13 insertions(+), 42 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index c624e47a7..c433404fd 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -34,13 +34,11 @@ type StorageMinerActorState struct { DePledgeTime types.BigInt // All sectors this miner has committed. - Sectors cid.Cid // TODO: Using a HAMT for now, needs to be an AMT once we implement it - SectorSetSize uint64 // TODO: the AMT should be able to tell us how many items are in it. This field won't be needed at that point + Sectors cid.Cid // TODO: Using a HAMT for now, needs to be an AMT once we implement it // Sectors this miner is currently mining. It is only updated // when a PoSt is submitted (not as each new sector commitment is added). - ProvingSet cid.Cid - ProvingSetSize uint64 + ProvingSet cid.Cid // Faulty sectors reported since last SubmitPost, // up to the current proving period's challenge time. @@ -269,9 +267,13 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex // // Note: Proving period is a function of sector size; small sectors take less // time to prove than large sectors do. Sector size is selected when pledging. - if self.ProvingSetSize == 0 { + pss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet) + if lerr != nil { + return nil, aerrors.Escalate(lerr, "could not load proving set node") + } + + if pss.Count == 0 { self.ProvingSet = self.Sectors - self.ProvingSetSize = self.SectorSetSize self.ProvingPeriodEnd = vmctx.BlockHeight() + build.ProvingPeriodDuration } @@ -367,7 +369,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, pss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet) if lerr != nil { - return nil, aerrors.Escalate(lerr, "could not load sector set node") + return nil, aerrors.Escalate(lerr, "could not load proving set node") } var sectorInfos []sectorbuilder.SectorInfo @@ -413,7 +415,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, ss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet) if lerr != nil { - return nil, aerrors.Escalate(lerr, "could not load sector set node") + return nil, aerrors.Escalate(lerr, "could not load proving set node") } if err := ss.BatchDelete(params.DoneSet.All()); err != nil { @@ -429,7 +431,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, } oldPower := self.Power - self.Power = types.BigMul(types.NewInt(self.ProvingSetSize-uint64(len(faults))), + self.Power = types.BigMul(types.NewInt(pss.Count-uint64(len(faults))), mi.SectorSize) enc, err := SerializeParams(&UpdateStorageParams{Delta: types.BigSub(self.Power, oldPower)}) @@ -443,7 +445,6 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, } self.ProvingSet = self.Sectors - self.ProvingSetSize = self.SectorSetSize self.NextDoneSet = params.DoneSet c, err := vmctx.Storage().Put(self) diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index 04d9fd163..388ae29c8 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -197,7 +197,7 @@ func (t *StorageMinerActorState) MarshalCBOR(w io.Writer) error { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write([]byte{142}); err != nil { + if _, err := w.Write([]byte{140}); err != nil { return err } @@ -223,22 +223,12 @@ func (t *StorageMinerActorState) MarshalCBOR(w io.Writer) error { return xerrors.Errorf("failed to write cid field t.Sectors: %w", err) } - // t.t.SectorSetSize (uint64) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorSetSize)); err != nil { - return err - } - // t.t.ProvingSet (cid.Cid) if err := cbg.WriteCid(w, t.ProvingSet); err != nil { return xerrors.Errorf("failed to write cid field t.ProvingSet: %w", err) } - // t.t.ProvingSetSize (uint64) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.ProvingSetSize)); err != nil { - return err - } - // t.t.CurrentFaultSet (types.BitField) if err := t.CurrentFaultSet.MarshalCBOR(w); err != nil { return err @@ -287,7 +277,7 @@ func (t *StorageMinerActorState) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 14 { + if extra != 12 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -333,16 +323,6 @@ func (t *StorageMinerActorState) UnmarshalCBOR(r io.Reader) error { t.Sectors = c } - // t.t.SectorSetSize (uint64) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.SectorSetSize = extra // t.t.ProvingSet (cid.Cid) { @@ -355,16 +335,6 @@ func (t *StorageMinerActorState) UnmarshalCBOR(r io.Reader) error { t.ProvingSet = c } - // t.t.ProvingSetSize (uint64) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.ProvingSetSize = extra // t.t.CurrentFaultSet (types.BitField) { From 6c48ab3be4faf37dcf622ff20a16f3e815b1db7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 20:38:58 +0200 Subject: [PATCH 17/23] Compute post more than once --- chain/actors/actor_miner.go | 1 + storage/miner.go | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index c433404fd..80cd9a9f2 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -445,6 +445,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, } self.ProvingSet = self.Sectors + self.ProvingPeriodEnd = nextProvingPeriodEnd self.NextDoneSet = params.DoneSet c, err := vmctx.Storage().Put(self) diff --git a/storage/miner.go b/storage/miner.go index 1eb56bf2c..7642b426a 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -303,15 +303,20 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error GasPrice: types.NewInt(1), } - _, err = m.api.MpoolPushMessage(ctx, msg) + smsg, err := m.api.MpoolPushMessage(ctx, msg) if err != nil { ret <- xerrors.Errorf("pushing message to mpool: %w", err) return } // make sure it succeeds... - // m.api.ChainWaitMsg() + _, err = m.api.ChainWaitMsg(ctx, smsg.Cid()) + if err != nil { + return + } + // TODO: check receipt + m.schedulePoSt(ctx, nil) }() return ret, sourceTs.MinTicketBlock(), nil From 72e003ef9e3036753fbc9dcfdbe36fdd78215d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 20:42:43 +0200 Subject: [PATCH 18/23] actors: remove debug logging from SubmitPost --- chain/actors/actor_miner.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index 80cd9a9f2..8cf5ef89d 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -2,7 +2,6 @@ package actors import ( "context" - "encoding/base64" "fmt" "github.com/filecoin-project/go-lotus/build" @@ -297,12 +296,6 @@ type SubmitPoStParams struct { // TODO: this is a dummy method that allows us to plumb in other parts of the // system for now. func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitPoStParams) (_ []byte, paerr ActorError) { - defer func() { - if paerr != nil { - log.Error(paerr) - } - }() - oldstate, self, err := loadState(vmctx) if err != nil { return nil, err @@ -345,16 +338,13 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, } } - var dbgRandH uint64 var seed [sectorbuilder.CommLen]byte { var rand []byte var err ActorError if !lateSubmission { - dbgRandH = self.ProvingPeriodEnd - build.PoSTChallangeTime rand, err = vmctx.GetRandomness(self.ProvingPeriodEnd - build.PoSTChallangeTime) } else { - dbgRandH = nextProvingPeriodEnd - build.PoSTChallangeTime rand, err = vmctx.GetRandomness(nextProvingPeriodEnd - build.PoSTChallangeTime) } if err != nil { @@ -396,17 +386,14 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, faults := self.CurrentFaultSet.All() - log.Infof("VerifyPost; rh=%d r=%s pLen=%d", dbgRandH, base64.StdEncoding.EncodeToString(seed[:]), len(params.Proof)) if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize.Uint64(), sectorbuilder.NewSortedSectorInfo(sectorInfos), seed, params.Proof, faults); !ok || lerr != nil { if lerr != nil { // TODO: study PoST errors - log.Infof("Post Verify Error: %s", lerr) return nil, aerrors.Absorb(lerr, 4, "PoST error") } if !ok { - log.Info("post verification FAILED") return nil, aerrors.New(4, "PoST invalid") } } From fdb45aeeaa8b4b21d94a4ae8e434b0b0bc7afecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 22:17:26 +0200 Subject: [PATCH 19/23] pond: +20k, +200k buttons --- chain/events/tscache.go | 5 +++-- lotuspond/front/src/Address.js | 14 +++++++------- lotuspond/front/src/FullNode.js | 10 +++++----- lotuspond/front/src/NodeList.js | 8 ++++---- storage/miner.go | 2 +- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/chain/events/tscache.go b/chain/events/tscache.go index 33493a4b8..a0d85e6e2 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -70,13 +70,14 @@ func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) { return nil, xerrors.Errorf("tipSetCache.get: requested tipset not in cache (req: %d, cache head: %d)", height, headH) } - tailH := tsc.cache[(tsc.start-tsc.len+1)%len(tsc.cache)].Height() + clen := len(tsc.cache) + tailH := tsc.cache[((tsc.start-tsc.len+1)% clen + clen) % clen].Height() if height < tailH { return tsc.storage(context.TODO(), height, tsc.cache[tailH]) } - return tsc.cache[int(height-tailH+1)%len(tsc.cache)], nil + return tsc.cache[(int(height-tailH+1) % clen + clen) % clen], nil } func (tsc *tipSetCache) best() *types.TipSet { diff --git a/lotuspond/front/src/Address.js b/lotuspond/front/src/Address.js index b41f3cdcb..64984716d 100644 --- a/lotuspond/front/src/Address.js +++ b/lotuspond/front/src/Address.js @@ -84,16 +84,16 @@ class Address extends React.Component { return info } - add10k = async () => { - [...Array(10).keys()].map(() => async () => await this.props.add1k(this.props.addr)).reduce(async (p, c) => [await p, await c()], Promise.resolve(null)) + add200k = async () => { + [...Array(10).keys()].map(() => async () => await this.props.add20k(this.props.addr)).reduce(async (p, c) => [await p, await c()], Promise.resolve(null)) } render() { - let add1k = - if(this.props.add1k) { - add1k =   this.props.add1k(this.props.addr)}>[+1k] + let add20k = + if(this.props.add20k) { + add20k =   this.props.add20k(this.props.addr)}>[+20k] if (this.props.add10k) { - add1k = {add1k} [+10k] + add20k = {add20k} [+200k] } } let addr = truncAddr(this.props.addr, this.props.short ? 12 : 17) @@ -133,7 +133,7 @@ class Address extends React.Component { minerInfo =  Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%) } - return {addr}{balance}{actInfo}{nonce}{add1k}{transfer}{minerInfo} + return {addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo} } } diff --git a/lotuspond/front/src/FullNode.js b/lotuspond/front/src/FullNode.js index edf620579..29a805273 100644 --- a/lotuspond/front/src/FullNode.js +++ b/lotuspond/front/src/FullNode.js @@ -15,7 +15,7 @@ class FullNode extends React.Component { this.newSecpAddr = this.newSecpAddr.bind(this) this.newBLSAddr = this.newBLSAddr.bind(this) this.startStorageMiner = this.startStorageMiner.bind(this) - this.add1k = this.add1k.bind(this) + this.add20k = this.add20k.bind(this) this.explorer = this.explorer.bind(this) this.client = this.client.bind(this) this.stop = this.stop.bind(this) @@ -84,8 +84,8 @@ class FullNode extends React.Component { this.props.spawnStorageNode(this.props.node.Repo, this.props.client) } - async add1k(to) { - await this.props.give1k(to) + async add20k(to) { + await this.props.give20k(to) } explorer() { @@ -123,14 +123,14 @@ class FullNode extends React.Component { let storageMine = let addresses = this.state.addrs.map((addr) => { - let line =
+ let line =
if (this.state.defaultAddr === addr) { line = {line} } return
{line}
}) let paychannels = this.state.paychs.map((addr, ak) => { - const line =
+ const line =
const vouchers = this.state.vouchers[ak].map(voucher => { let extra = if(voucher.Extra) { diff --git a/lotuspond/front/src/NodeList.js b/lotuspond/front/src/NodeList.js index 093a336c4..0466a5eb9 100644 --- a/lotuspond/front/src/NodeList.js +++ b/lotuspond/front/src/NodeList.js @@ -27,7 +27,7 @@ class NodeList extends React.Component { this.spawnStorageNode = this.spawnStorageNode.bind(this) this.connMgr = this.connMgr.bind(this) this.consensus = this.consensus.bind(this) - this.transfer1kFrom1 = this.transfer1kFrom1.bind(this) + this.transfer20kFrom1 = this.transfer20kFrom1.bind(this) this.getNodes() } @@ -52,7 +52,7 @@ class NodeList extends React.Component { node={{...node}} client={client} pondClient={this.props.client} - give1k={this.transfer1kFrom1} + give20k={this.transfer20kFrom1} mountWindow={this.props.mountWindow} spawnStorageNode={this.spawnStorageNode} stop={this.stopNode(node.ID, onClose)} @@ -81,7 +81,7 @@ class NodeList extends React.Component { this.setState({existingLoaded: true, nodes: nodes}) } - async transfer1kFrom1(to) { + async transfer20kFrom1(to) { const addrss = await this.state.nodes[1].conn.call('Filecoin.WalletList', []) const [bestaddr, bal] = await addrss.map(async addr => { let balance = 0 @@ -96,7 +96,7 @@ class NodeList extends React.Component { await pushMessage(this.state.nodes[1].conn, bestaddr, { To: to, From: bestaddr, - Value: "1000", + Value: "20000", }) } diff --git a/storage/miner.go b/storage/miner.go index 7642b426a..2e07701bc 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -194,7 +194,7 @@ func (m *Miner) schedulePoSt(ctx context.Context, baseTs *types.TipSet) { m.schedLk.Lock() if m.postSched >= ppe { - log.Warn("schedulePoSt already called for proving period >= %d", m.postSched) + log.Warnf("schedulePoSt already called for proving period >= %d", m.postSched) m.schedLk.Unlock() return } From 5fd98b7d27e02bc0407a31b90df24131116d32f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 22:24:01 +0200 Subject: [PATCH 20/23] post: Address review --- chain/actors/actor_miner.go | 4 ++-- chain/events/tscache.go | 4 ++-- chain/types/bigint.go | 5 ++++- chain/vm/vm.go | 4 ++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index 8cf5ef89d..18c656004 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -33,7 +33,7 @@ type StorageMinerActorState struct { DePledgeTime types.BigInt // All sectors this miner has committed. - Sectors cid.Cid // TODO: Using a HAMT for now, needs to be an AMT once we implement it + Sectors cid.Cid // Sectors this miner is currently mining. It is only updated // when a PoSt is submitted (not as each new sector commitment is added). @@ -295,7 +295,7 @@ type SubmitPoStParams struct { // TODO: this is a dummy method that allows us to plumb in other parts of the // system for now. -func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitPoStParams) (_ []byte, paerr ActorError) { +func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitPoStParams) ([]byte, ActorError) { oldstate, self, err := loadState(vmctx) if err != nil { return nil, err diff --git a/chain/events/tscache.go b/chain/events/tscache.go index a0d85e6e2..e6d492bfa 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -71,13 +71,13 @@ func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) { } clen := len(tsc.cache) - tailH := tsc.cache[((tsc.start-tsc.len+1)% clen + clen) % clen].Height() + tailH := tsc.cache[((tsc.start-tsc.len+1)%clen+clen)%clen].Height() if height < tailH { return tsc.storage(context.TODO(), height, tsc.cache[tailH]) } - return tsc.cache[(int(height-tailH+1) % clen + clen) % clen], nil + return tsc.cache[(int(height-tailH+1)%clen+clen)%clen], nil } func (tsc *tipSetCache) best() *types.TipSet { diff --git a/chain/types/bigint.go b/chain/types/bigint.go index ed37930ff..de95d0a61 100644 --- a/chain/types/bigint.go +++ b/chain/types/bigint.go @@ -107,7 +107,10 @@ func (bi *BigInt) MarshalCBOR(w io.Writer) error { return zero.MarshalCBOR(w) } - tag := uint64(^(bi.Sign()|1)+6) >> 1 + tag := uint64(2) + if bi.Sign() < 0 { + tag = 3 + } header := cbg.CborEncodeMajorType(cbg.MajTag, tag) if _, err := w.Write(header); err != nil { diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 1666228b3..644203564 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -70,6 +70,10 @@ func (vmc *VMContext) GetRandomness(height uint64) ([]byte, aerrors.ActorError) hts := vmc.vm.cs.GetHeaviestTipSet() relHeight := int(hts.Height() - height) + if relHeight < 0 { + return nil, aerrors.Newf(1, "negative relHeight in GetRandomness: %d", relHeight) + } + res, err := vmc.vm.cs.GetRandomness(vmc.ctx, hts, nil, relHeight) if err != nil { return nil, aerrors.Escalate(err, "could not get randomness") From 73d1182121e474796ea7093a715820c7cc53ddbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 19 Sep 2019 22:34:18 +0200 Subject: [PATCH 21/23] post: More review addressing --- chain/store/store.go | 5 +++++ storage/miner.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/chain/store/store.go b/chain/store/store.go index 204b7de98..ad9038bb1 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/json" "fmt" + "github.com/filecoin-project/go-lotus/build" "sync" amt "github.com/filecoin-project/go-amt-ipld" @@ -755,6 +756,10 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h uint64, ts *types return nil, xerrors.Errorf("looking for tipset with height less than start point") } + if ts.Height()-h > build.ForkLengthThreshold { + log.Warnf("expensive call to GetTipsetByHeight, seeking %d levels", ts.Height()-h) + } + for { mtb := ts.MinTicketBlock() if h >= ts.Height()-uint64(len(mtb.Tickets)) { diff --git a/storage/miner.go b/storage/miner.go index 2e07701bc..00c69ea87 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -250,7 +250,7 @@ func (m *Miner) maybeDoPost(ctx context.Context, ts *types.TipSet) (<-chan error return nil, nil, xerrors.Errorf("failed to get proving period end for miner: %w", err) } - if ppe < ts.Height() { + if ts.Height() > ppe { log.Warnf("skipping post, supplied tipset too high: ppe=%d, ts.H=%d", ppe, ts.Height()) return nil, nil, nil } From 394edc6317ce38a275329e8bcef74ed3f176c27f Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 19 Sep 2019 19:54:52 -0700 Subject: [PATCH 22/23] refactor to use 'randomness' as input to new vm creation --- chain/actors/actors_test.go | 3 ++- chain/actors/harness2_test.go | 2 +- chain/gen/gen.go | 2 +- chain/gen/mining.go | 3 ++- chain/gen/utils.go | 2 +- chain/stmgr/call.go | 8 +++++--- chain/stmgr/stmgr.go | 4 +++- chain/stmgr/utils.go | 4 ++-- chain/store/store.go | 23 ++++++++++++++--------- chain/sync.go | 5 +++-- chain/vm/vm.go | 35 +++++++++++++++++++++++++++-------- go.sum | 1 - node/impl/full/chain.go | 2 +- 13 files changed, 62 insertions(+), 32 deletions(-) diff --git a/chain/actors/actors_test.go b/chain/actors/actors_test.go index 6611e8c51..5a3be6c13 100644 --- a/chain/actors/actors_test.go +++ b/chain/actors/actors_test.go @@ -51,7 +51,8 @@ func setupVMTestEnv(t *testing.T) (*vm.VM, []address.Address) { cs := store.NewChainStore(bs, nil) - vm, err := vm.NewVM(stateroot, 1, maddr, cs) + // TODO: should probabaly mock out the randomness bit, nil works for now + vm, err := vm.NewVM(stateroot, 1, nil, maddr, cs) if err != nil { t.Fatal(err) } diff --git a/chain/actors/harness2_test.go b/chain/actors/harness2_test.go index 55d766a8c..3e08a2bc2 100644 --- a/chain/actors/harness2_test.go +++ b/chain/actors/harness2_test.go @@ -158,7 +158,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness { t.Fatal(err) } h.cs = store.NewChainStore(h.bs, nil) - h.vm, err = vm.NewVM(stateroot, 1, h.HI.Miner, h.cs) + h.vm, err = vm.NewVM(stateroot, 1, nil, h.HI.Miner, h.cs) if err != nil { t.Fatal(err) } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 9a06af5af..e4b700196 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -360,7 +360,7 @@ type mca struct { } func (mca mca) ChainGetRandomness(ctx context.Context, pts *types.TipSet, ticks []*types.Ticket, lb int) ([]byte, error) { - return mca.sm.ChainStore().GetRandomness(ctx, pts, ticks, lb) + return mca.sm.ChainStore().GetRandomness(ctx, pts, ticks, int64(lb)) } func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) { diff --git a/chain/gen/mining.go b/chain/gen/mining.go index 0d484f4ca..3b34e5d56 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -27,7 +27,8 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal height := parents.Height() + uint64(len(tickets)) - vmi, err := vm.NewVM(st, height, miner, sm.ChainStore()) + r := vm.NewChainRand(sm.ChainStore(), parents, tickets) + vmi, err := vm.NewVM(st, height, r, miner, sm.ChainStore()) if err != nil { return nil, err } diff --git a/chain/gen/utils.go b/chain/gen/utils.go index 7ee1053de..1a1f9fcb4 100644 --- a/chain/gen/utils.go +++ b/chain/gen/utils.go @@ -169,7 +169,7 @@ func mustEnc(i cbg.CBORMarshaler) []byte { } func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, error) { - vm, err := vm.NewVM(sroot, 0, actors.NetworkAddress, cs) + vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs) if err != nil { return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 607273724..3c5af3079 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -11,8 +11,8 @@ import ( "golang.org/x/xerrors" ) -func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, bheight uint64) (*types.MessageReceipt, error) { - vmi, err := vm.NewVM(bstate, bheight, actors.NetworkAddress, sm.cs) +func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight uint64) (*types.MessageReceipt, error) { + vmi, err := vm.NewVM(bstate, bheight, r, actors.NetworkAddress, sm.cs) if err != nil { return nil, xerrors.Errorf("failed to set up vm: %w", err) } @@ -57,5 +57,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. return nil, err } - return sm.CallRaw(ctx, msg, state, ts.Height()) + r := vm.NewChainRand(sm.cs, ts, nil) + + return sm.CallRaw(ctx, msg, state, r, ts.Height()) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 03f14a371..e72e53d3f 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -78,7 +78,9 @@ func (sm *StateManager) computeTipSetState(cids []cid.Cid) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("recursive TipSetState failed: %w", err) } - vmi, err := vm.NewVM(pstate, ts.Height(), address.Undef, sm.cs) + r := vm.NewChainRand(sm.cs, ts, nil) + + vmi, err := vm.NewVM(pstate, ts.Height(), r, address.Undef, sm.cs) if err != nil { return cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err) } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index a9707acc9..07e6115ec 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -22,7 +22,7 @@ func GetMinerWorker(ctx context.Context, sm *StateManager, st cid.Cid, maddr add To: maddr, From: maddr, Method: actors.MAMethods.GetWorkerAddr, - }, st, 0) + }, st, nil, 0) if err != nil { return address.Undef, xerrors.Errorf("callRaw failed: %w", err) } @@ -48,7 +48,7 @@ func GetMinerOwner(ctx context.Context, sm *StateManager, st cid.Cid, maddr addr To: maddr, From: maddr, Method: actors.MAMethods.GetOwner, - }, st, 0) + }, st, nil, 0) if err != nil { return address.Undef, xerrors.Errorf("callRaw failed: %w", err) } diff --git a/chain/store/store.go b/chain/store/store.go index 204b7de98..2298db7ef 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -701,16 +701,20 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) { return NewFullTipSet(out), nil } -func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int) ([]byte, error) { - if lb < len(tickets) { +func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int64) ([]byte, error) { + if lb < 0 { + return nil, fmt.Errorf("negative lookback parameters are not valid (got %d)", lb) + } + lt := int64(len(tickets)) + if lb < lt { log.Warn("self sampling randomness. this should be extremely rare, if you see this often it may be a bug") - t := tickets[len(tickets)-(1+lb)] + t := tickets[lt-(1+lb)] return t.VDFResult, nil } - nv := lb - len(tickets) + nv := lb - lt nextCids := pts.Cids() for { @@ -720,13 +724,14 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tick } mtb := nts.MinTicketBlock() - if nv < len(mtb.Tickets) { - t := mtb.Tickets[len(mtb.Tickets)-(1+nv)] - log.Infof("Returning randomness: H:%d, t:%d, mtb:%s", nts.Height(), len(mtb.Tickets)-(1+nv), mtb.Cid()) + lt := int64(len(mtb.Tickets)) + if nv < lt { + t := mtb.Tickets[lt-(1+nv)] + log.Infof("Returning randomness: H:%d, t:%d, mtb:%s", nts.Height(), lt-(1+nv), mtb.Cid()) return t.VDFResult, nil } - nv -= len(mtb.Tickets) + nv -= lt // special case for lookback behind genesis block // TODO(spec): this is not in the spec, need to sync that @@ -735,7 +740,7 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tick t := mtb.Tickets[0] rval := t.VDFResult - for i := 0; i < nv; i++ { + for i := int64(0); i < nv; i++ { h := sha256.Sum256(rval) rval = h[:] } diff --git a/chain/sync.go b/chain/sync.go index 3af36f57f..b9de70f4e 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -313,7 +313,7 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet) for _, b := range fts.Blocks { if err := syncer.ValidateBlock(ctx, b); err != nil { - return err + return xerrors.Errorf("validating block %s: %w", b.Cid(), err) } } return nil @@ -440,7 +440,8 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err return xerrors.Errorf("miner created a block but was not a winner") } - vmi, err := vm.NewVM(stateroot, h.Height, h.Miner, syncer.store) + r := vm.NewChainRand(syncer.store, baseTs, h.Tickets) + vmi, err := vm.NewVM(stateroot, h.Height, r, h.Miner, syncer.store) if err != nil { return xerrors.Errorf("failed to instantiate VM: %w", err) } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 644203564..f5c8a21b1 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -67,14 +67,8 @@ func (vmc *VMContext) Message() *types.Message { } func (vmc *VMContext) GetRandomness(height uint64) ([]byte, aerrors.ActorError) { - hts := vmc.vm.cs.GetHeaviestTipSet() - relHeight := int(hts.Height() - height) - if relHeight < 0 { - return nil, aerrors.Newf(1, "negative relHeight in GetRandomness: %d", relHeight) - } - - res, err := vmc.vm.cs.GetRandomness(vmc.ctx, hts, nil, relHeight) + res, err := vmc.vm.rand.GetRandomness(vmc.ctx, int64(height)) if err != nil { return nil, aerrors.Escalate(err, "could not get randomness") } @@ -294,9 +288,10 @@ type VM struct { blockHeight uint64 blockMiner address.Address inv *invoker + rand Rand } -func NewVM(base cid.Cid, height uint64, maddr address.Address, cs *store.ChainStore) (*VM, error) { +func NewVM(base cid.Cid, height uint64, r Rand, maddr address.Address, cs *store.ChainStore) (*VM, error) { buf := bufbstore.NewBufferedBstore(cs.Blockstore()) cst := hamt.CSTFromBstore(buf) state, err := state.LoadStateTree(cst, base) @@ -313,9 +308,33 @@ func NewVM(base cid.Cid, height uint64, maddr address.Address, cs *store.ChainSt blockHeight: height, blockMiner: maddr, inv: newInvoker(), + rand: r, }, nil } +type Rand interface { + GetRandomness(ctx context.Context, h int64) ([]byte, error) +} + +type chainRand struct { + cs *store.ChainStore + pts *types.TipSet + tickets []*types.Ticket +} + +func NewChainRand(cs *store.ChainStore, pts *types.TipSet, tickets []*types.Ticket) Rand { + return &chainRand{ + cs: cs, + pts: pts, + tickets: tickets, + } +} + +func (cr *chainRand) GetRandomness(ctx context.Context, h int64) ([]byte, error) { + lb := (int64(cr.pts.Height()) + int64(len(cr.tickets))) - h + return cr.cs.GetRandomness(ctx, cr.pts, cr.tickets, lb) +} + type ApplyRet struct { types.MessageReceipt ActorErr aerrors.ActorError diff --git a/go.sum b/go.sum index f2f20f3b9..a4bfa81ef 100644 --- a/go.sum +++ b/go.sum @@ -68,7 +68,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/filecoin-project/go-amt-ipld v0.0.0-20190917221444-2ed85149c65d/go.mod h1:lKjJYPg2kwbav5f78i5YA8kGccnZn18IySbpneXvaQs= github.com/filecoin-project/go-amt-ipld v0.0.0-20190919045431-3650716fff16 h1:NzojcJU1VbS6zdLG13JMYis/cQy/MrN3rxmZRq56jKA= github.com/filecoin-project/go-amt-ipld v0.0.0-20190919045431-3650716fff16/go.mod h1:lKjJYPg2kwbav5f78i5YA8kGccnZn18IySbpneXvaQs= github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543 h1:aMJGfgqe1QDhAVwxRg5fjCRF533xHidiKsugk7Vvzug= diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 94fb5717e..a9e0482c5 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -45,7 +45,7 @@ func (a *ChainAPI) ChainHead(context.Context) (*types.TipSet, error) { } func (a *ChainAPI) ChainGetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int) ([]byte, error) { - return a.Chain.GetRandomness(ctx, pts, tickets, lb) + return a.Chain.GetRandomness(ctx, pts, tickets, int64(lb)) } func (a *ChainAPI) ChainWaitMsg(ctx context.Context, msg cid.Cid) (*api.MsgWait, error) { From 9d36a499b607c26bc5f6d1ab8afba298c2518b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 20 Sep 2019 14:22:46 +0200 Subject: [PATCH 23/23] post merge fixes --- api/struct.go | 2 +- chain/gen/gen.go | 2 +- chain/gen/mining.go | 2 +- chain/stmgr/call.go | 2 +- chain/stmgr/stmgr.go | 7 ++++++- chain/store/store.go | 7 +++---- chain/sync.go | 4 ++-- chain/vm/vm.go | 12 +++++++----- node/impl/full/chain.go | 2 +- 9 files changed, 23 insertions(+), 17 deletions(-) diff --git a/api/struct.go b/api/struct.go index 84163742d..e6db41d14 100644 --- a/api/struct.go +++ b/api/struct.go @@ -82,7 +82,7 @@ type FullNodeStruct struct { StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` - StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"` + StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"` StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` diff --git a/chain/gen/gen.go b/chain/gen/gen.go index e4b700196..d7d1bef86 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -360,7 +360,7 @@ type mca struct { } func (mca mca) ChainGetRandomness(ctx context.Context, pts *types.TipSet, ticks []*types.Ticket, lb int) ([]byte, error) { - return mca.sm.ChainStore().GetRandomness(ctx, pts, ticks, int64(lb)) + return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), ticks, int64(lb)) } func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) { diff --git a/chain/gen/mining.go b/chain/gen/mining.go index 3b34e5d56..af0adccb9 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -27,7 +27,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal height := parents.Height() + uint64(len(tickets)) - r := vm.NewChainRand(sm.ChainStore(), parents, tickets) + r := vm.NewChainRand(sm.ChainStore(), parents.Cids(), parents.Height(), tickets) vmi, err := vm.NewVM(st, height, r, miner, sm.ChainStore()) if err != nil { return nil, err diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index ba375a2d6..a2fae8c63 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -58,7 +58,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. return nil, err } - r := vm.NewChainRand(sm.cs, ts, nil) + r := vm.NewChainRand(sm.cs, ts.Cids(), ts.Height(), nil) return sm.CallRaw(ctx, msg, state, r, ts.Height()) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 7fc0d8205..1d1afd846 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -77,7 +77,12 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl return cid.Undef, xerrors.Errorf("recursive TipSetState failed: %w", err) } - r := vm.NewChainRand(sm.cs, blks[0], nil) + cids := make([]cid.Cid, len(blks)) + for i, v := range blks { + cids[i] = v.Cid() + } + + r := vm.NewChainRand(sm.cs, cids, blks[0].Height, nil) vmi, err := vm.NewVM(pstate, blks[0].Height, r, address.Undef, sm.cs) if err != nil { diff --git a/chain/store/store.go b/chain/store/store.go index a797524d4..e95ccb2a7 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -702,7 +702,7 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) { return NewFullTipSet(out), nil } -func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int64) ([]byte, error) { +func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, tickets []*types.Ticket, lb int64) ([]byte, error) { if lb < 0 { return nil, fmt.Errorf("negative lookback parameters are not valid (got %d)", lb) } @@ -717,9 +717,8 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tick nv := lb - lt - nextCids := pts.Cids() for { - nts, err := cs.LoadTipSet(nextCids) + nts, err := cs.LoadTipSet(blks) if err != nil { return nil, err } @@ -748,7 +747,7 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tick return rval, nil } - nextCids = mtb.Parents + blks = mtb.Parents } } diff --git a/chain/sync.go b/chain/sync.go index b9de70f4e..1ebb2b9e9 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -422,7 +422,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err return xerrors.Errorf("validating block tickets failed: %w", err) } - rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs, h.Tickets, build.RandomnessLookback) + rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), h.Tickets, build.RandomnessLookback) if err != nil { return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err) } @@ -440,7 +440,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err return xerrors.Errorf("miner created a block but was not a winner") } - r := vm.NewChainRand(syncer.store, baseTs, h.Tickets) + r := vm.NewChainRand(syncer.store, baseTs.Cids(), baseTs.Height(), h.Tickets) vmi, err := vm.NewVM(stateroot, h.Height, r, h.Miner, syncer.store) if err != nil { return xerrors.Errorf("failed to instantiate VM: %w", err) diff --git a/chain/vm/vm.go b/chain/vm/vm.go index f5c8a21b1..c83187503 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -318,21 +318,23 @@ type Rand interface { type chainRand struct { cs *store.ChainStore - pts *types.TipSet + blks []cid.Cid + bh uint64 tickets []*types.Ticket } -func NewChainRand(cs *store.ChainStore, pts *types.TipSet, tickets []*types.Ticket) Rand { +func NewChainRand(cs *store.ChainStore, blks []cid.Cid, bheight uint64, tickets []*types.Ticket) Rand { return &chainRand{ cs: cs, - pts: pts, + blks: blks, + bh: bheight, tickets: tickets, } } func (cr *chainRand) GetRandomness(ctx context.Context, h int64) ([]byte, error) { - lb := (int64(cr.pts.Height()) + int64(len(cr.tickets))) - h - return cr.cs.GetRandomness(ctx, cr.pts, cr.tickets, lb) + lb := (int64(cr.bh) + int64(len(cr.tickets))) - h + return cr.cs.GetRandomness(ctx, cr.blks, cr.tickets, lb) } type ApplyRet struct { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index a9e0482c5..51de87165 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -45,7 +45,7 @@ func (a *ChainAPI) ChainHead(context.Context) (*types.TipSet, error) { } func (a *ChainAPI) ChainGetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int) ([]byte, error) { - return a.Chain.GetRandomness(ctx, pts, tickets, int64(lb)) + return a.Chain.GetRandomness(ctx, pts.Cids(), tickets, int64(lb)) } func (a *ChainAPI) ChainWaitMsg(ctx context.Context, msg cid.Cid) (*api.MsgWait, error) {