Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rought PoST method #207

Merged
merged 6 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ const DealVoucherSkewLimit = 10
const ForkLengthThreshold = 20
const RandomnessLookback = 20

const ProvingPeriodDuration = 2 * 60 // an hour, for now
const PoSTChallangeTime = 1 * 60

// TODO: Move other important consts here
132 changes: 120 additions & 12 deletions chain/actors/actor_miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package actors

import (
"context"
"fmt"

"github.com/filecoin-project/go-lotus/build"
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types"
Expand All @@ -12,10 +14,10 @@ import (
"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"
)

var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now
const POST_SECTORS_COUNT = 8192

type StorageMinerActor struct{}
Expand Down Expand Up @@ -118,9 +120,10 @@ type maMethods struct {
IsLate uint64
PaymentVerifyInclusion uint64
PaymentVerifySector uint64
AddFaults uint64
}

var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}

func (sma StorageMinerActor) Exports() []interface{} {
return []interface{}{
Expand All @@ -142,6 +145,7 @@ func (sma StorageMinerActor) Exports() []interface{} {
//16: sma.IsLate,
17: sma.PaymentVerifyInclusion,
18: sma.PaymentVerifySector,
19: nil,
}
}

Expand Down Expand Up @@ -247,11 +251,6 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
return nil, aerrors.New(3, "not enough collateral")
}

// ensure that the miner cannot commit more sectors than can be proved with a single PoSt
if self.SectorSetSize >= POST_SECTORS_COUNT {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was removed from spec.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, i chatted with @dignifiedquire.

This was removed from the spec because technically, rational post can handle an unlimited number of sectors. We agreed though that for practical purposes, there should be some limit (otherwise there are dos vectors with 'infinite' sized arrays of sectors being passed around, and other such nonsense).

Let's keep this code in for now, and file some spec issues to fix it up

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my take: there should be none with current construction, however we shouldn't assume so for future construction and backward compatibility, so we should pick a number

return nil, aerrors.New(4, "too many sectors")
}

// Note: There must exist a unique index in the miner's sector set for each
// sector ID. The `faults`, `recovered`, and `done` parameters of the
// SubmitPoSt method express indices into this sector set.
Expand All @@ -272,7 +271,7 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
if self.ProvingSetSize == 0 {
self.ProvingSet = self.Sectors
self.ProvingSetSize = self.SectorSetSize
self.ProvingPeriodEnd = vmctx.BlockHeight() + ProvingPeriodDuration
self.ProvingPeriodEnd = vmctx.BlockHeight() + build.ProvingPeriodDuration
}

nstate, err := vmctx.Storage().Put(self)
Expand All @@ -287,6 +286,8 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex
}

type SubmitPoStParams struct {
Proof []byte
DoneSet types.BitField
// TODO: once the spec changes finish, we have more work to do here...
}

Expand All @@ -307,13 +308,116 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext,
return nil, aerrors.New(1, "not authorized to submit post for miner")
}

oldProvingSetSize := self.ProvingSetSize
feesRequired := types.NewInt(0)
nextProvingPeriodEnd := self.ProvingPeriodEnd + build.ProvingPeriodDuration
if vmctx.BlockHeight() > nextProvingPeriodEnd {
return nil, aerrors.New(1, "PoSt submited too late")
}

self.ProvingSet = self.Sectors
self.ProvingSetSize = self.SectorSetSize
var lateSubmission bool
if vmctx.BlockHeight() > self.ProvingPeriodEnd {
//TODO late fee calc
lateSubmission = true
feesRequired = types.BigAdd(feesRequired, types.NewInt(1000))
Kubuxu marked this conversation as resolved.
Show resolved Hide resolved
}

//TODO temporary sector failure fees

msgVal := vmctx.Message().Value
if types.BigCmp(msgVal, feesRequired) < 0 {
return nil, aerrors.New(2, "not enough funds to pay post submission fees")
Kubuxu marked this conversation as resolved.
Show resolved Hide resolved
}

if types.BigCmp(msgVal, feesRequired) > 0 {
_, err := vmctx.Send(vmctx.Message().From, 0,
types.BigSub(msgVal, feesRequired), nil)
if err != nil {
return nil, aerrors.Wrap(err, "could not refund excess fees")
}
}

var seed [sectorbuilder.CommLen]byte
{
var rand []byte
var err ActorError
if !lateSubmission {
rand, err = vmctx.GetRandomness(self.ProvingPeriodEnd - build.PoSTChallangeTime)
} else {
rand, err = vmctx.GetRandomness(nextProvingPeriodEnd - build.PoSTChallangeTime)
}
if err != nil {
return nil, aerrors.Wrap(err, "could not get randomness for PoST")
}
if len(rand) < len(seed) {
return nil, aerrors.Escalate(fmt.Errorf("randomness too small (%d < %d)",
len(rand), len(seed)), "improper randomness")
}
copy(seed[:], rand)
}

pss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if lerr != nil {
return nil, aerrors.Escalate(lerr, "could not load sector set node")
}

var sectorInfos []sectorbuilder.SectorInfo
if err := pss.ForEach(func(id uint64, v *cbg.Deferred) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd pull this out into a separate function. Maybe we can dedupe some code with #205, can also do that later too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem is: either api or actor code (or both) would then have to convert types. API wants to use api.SectorInfo, chain wants to use sectorbuilder.SectorInfo.

var comms [][]byte
if err := cbor.DecodeInto(v.Raw, &comms); err != nil {
return xerrors.New("could not decode comms")
}
si := sectorbuilder.SectorInfo{
SectorID: id,
}
commR := comms[0]
if len(commR) != len(si.CommR) {
return xerrors.Errorf("commR length is wrong: %d", len(commR))
}
copy(si.CommR[:], commR)

sectorInfos = append(sectorInfos, si)

return nil
}); err != nil {
return nil, aerrors.Absorb(err, 3, "could not decode sectorset")
}

faults := self.CurrentFaultSet.All()

if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize.Uint64(),
sectorbuilder.NewSortedSectorInfo(sectorInfos), seed, params.Proof,
faults); !ok || lerr != nil {
if lerr != nil {
Kubuxu marked this conversation as resolved.
Show resolved Hide resolved
// TODO: study PoST errors
return nil, aerrors.Absorb(lerr, 4, "PoST error")
}
if !ok {
return nil, aerrors.New(4, "PoST invalid")
}
}
self.CurrentFaultSet = self.NextFaultSet
self.NextFaultSet = types.NewBitField()

ss, lerr := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
if lerr != nil {
return nil, aerrors.Escalate(lerr, "could not load sector set node")
}

if err := ss.BatchDelete(params.DoneSet.All()); err != nil {
// TODO: this could fail for system reasons (block not found) or for
// bad user input reasons (e.g. bad doneset). The latter should be a
// non-fatal error
return nil, aerrors.Escalate(err, "failed to delete sectors in done set")
}

self.ProvingSet, lerr = ss.Flush()
if lerr != nil {
return nil, aerrors.Escalate(lerr, "could not flush AMT")
}

oldPower := self.Power
self.Power = types.BigMul(types.NewInt(oldProvingSetSize), mi.SectorSize)
self.Power = types.BigMul(types.NewInt(self.ProvingSetSize-uint64(len(faults))),
mi.SectorSize)

enc, err := SerializeParams(&UpdateStorageParams{Delta: types.BigSub(self.Power, oldPower)})
if err != nil {
Expand All @@ -325,6 +429,10 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext,
return nil, err
}

self.ProvingSet = self.Sectors
self.ProvingSetSize = self.SectorSetSize
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, we can drop the Size fields, the AMT tracks its own cardinality (the HAMT didnt)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the Count field in AMT checked in any way so Eve can't change it at a whim?

self.NextDoneSet = params.DoneSet

c, err := vmctx.Storage().Put(self)
if err != nil {
return nil, err
Expand Down
13 changes: 13 additions & 0 deletions chain/types/bitfield.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ type BitField struct {
bits map[uint64]struct{}
}

func NewBitField() BitField {
return BitField{bits: make(map[uint64]struct{})}
}

// Set ...s bit in the BitField
func (bf BitField) Set(bit uint64) {
bf.bits[bit] = struct{}{}
Expand All @@ -29,6 +33,15 @@ func (bf BitField) Has(bit uint64) bool {
return ok
}

// All returns all set bits, in random order
func (bf BitField) All() []uint64 {
res := make([]uint64, 0, len(bf.bits))
for i := range bf.bits {
res = append(res, i)
}
return res
}

func (bf BitField) MarshalCBOR(w io.Writer) error {
ints := make([]uint64, 0, len(bf.bits))
for i := range bf.bits {
Expand Down
1 change: 1 addition & 0 deletions chain/types/vmcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type VMContext interface {
StateTree() (StateTree, aerrors.ActorError)
VerifySignature(sig *Signature, from address.Address, data []byte) aerrors.ActorError
ChargeGas(uint64) aerrors.ActorError
GetRandomness(height uint64) ([]byte, aerrors.ActorError)
}

type storageWrapper struct {
Expand Down
9 changes: 9 additions & 0 deletions chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ func (vmc *VMContext) Message() *types.Message {
return vmc.msg
}

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)
if err != nil {
return nil, aerrors.Escalate(err, "could not get randomness")
}
return res, nil
}

// Storage interface

func (vmc *VMContext) Put(i cbg.CBORMarshaler) (cid.Cid, aerrors.ActorError) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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-20190919045431-3650716fff16
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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ 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-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-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=
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=
Expand Down
12 changes: 9 additions & 3 deletions lib/sectorbuilder/sectorbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ func VerifyPieceInclusionProof(sectorSize uint64, pieceSize uint64, commP []byte
return sectorbuilder.VerifyPieceInclusionProof(sectorSize, pieceSize, commPa, commDa, proof)
}

func VerifyPost(sectorSize uint64, sortedCommRs [][CommLen]byte, challengeSeed [CommLen]byte, proofs [][]byte, faults []uint64) (bool, error) {
// sectorbuilder.VerifyPost()
panic("no")
type SortedSectorInfo = sectorbuilder.SortedSectorInfo
type SectorInfo = sectorbuilder.SectorInfo

func NewSortedSectorInfo(sectors []SectorInfo) SortedSectorInfo {
return sectorbuilder.NewSortedSectorInfo(sectors...)
}

func VerifyPost(sectorSize uint64, sectorInfo SortedSectorInfo, challengeSeed [CommLen]byte, proof []byte, faults []uint64) (bool, error) {
return sectorbuilder.VerifyPoSt(sectorSize, sectorInfo, challengeSeed, proof, faults)
}