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] 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() {