Skip to content

Commit

Permalink
Feat/winning post prep (#4005)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* Complete with failing tests

* Fix broken header and tests

* Please linter

* Remove car files

Co-authored-by: ZenGround0 <[email protected]>
  • Loading branch information
ZenGround0 and ZenGround0 authored Apr 21, 2020
1 parent bdd9b7a commit 3205573
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 186 deletions.
8 changes: 6 additions & 2 deletions internal/pkg/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ type Block struct {
// ElectionProof is the vrf proof giving this block's miner authoring rights
ElectionProof crypto.ElectionProof

// PoStProofs are the winning post proofs
PoStProofs []PoStProof `json:"PoStProofs"`

// DrandEntries contain the verifiable oracle randomness used to elect
// this block's author leader
DrandEntries []*drand.Entry
Expand Down Expand Up @@ -77,10 +80,10 @@ type Block struct {
}

// IndexMessagesField is the message field position in the encoded block
const IndexMessagesField = 9
const IndexMessagesField = 10

// IndexParentsField is the parents field position in the encoded block
const IndexParentsField = 4
const IndexParentsField = 5

// Cid returns the content id of this block.
func (b *Block) Cid() cid.Cid {
Expand Down Expand Up @@ -165,6 +168,7 @@ func (b *Block) SignatureData() []byte {
Messages: b.Messages,
StateRoot: b.StateRoot,
MessageReceipts: b.MessageReceipts,
PoStProofs: b.PoStProofs,
DrandEntries: b.DrandEntries,
Timestamp: b.Timestamp,
BLSAggregateSig: b.BLSAggregateSig,
Expand Down
21 changes: 20 additions & 1 deletion internal/pkg/block/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require"

blk "github.com/filecoin-project/go-filecoin/internal/pkg/block"
"github.com/filecoin-project/go-filecoin/internal/pkg/constants"
"github.com/filecoin-project/go-filecoin/internal/pkg/crypto"
"github.com/filecoin-project/go-filecoin/internal/pkg/drand"
e "github.com/filecoin-project/go-filecoin/internal/pkg/enccid"
Expand Down Expand Up @@ -61,6 +62,7 @@ func TestTriangleEncoding(t *testing.T) {
t.Run("encoding block with nonzero fields works", func(t *testing.T) {
// We should ensure that every field is set -- zero values might
// pass when non-zero values do not due to nil/null encoding.
posts := []blk.PoStProof{blk.NewPoStProof(constants.DevRegisteredPoStProof, []byte{0x07})}
b := &blk.Block{
Miner: newAddress(),
Ticket: blk.Ticket{VRFProof: []byte{0x01, 0x02, 0x03}},
Expand All @@ -86,6 +88,7 @@ func TestTriangleEncoding(t *testing.T) {
Type: crypto.SigTypeBLS,
Data: []byte{0x3},
},
PoStProofs: posts,
ForkSignaling: 6,
}
s := reflect.TypeOf(*b)
Expand All @@ -94,7 +97,7 @@ func TestTriangleEncoding(t *testing.T) {
// Also please add non zero fields to "b" and "diff" in TestSignatureData
// and add a new check that different values of the new field result in
// different output data.
require.Equal(t, 17, s.NumField()) // Note: this also counts private fields
require.Equal(t, 18, s.NumField()) // Note: this also counts private fields
testRoundTrip(t, b)
})
}
Expand Down Expand Up @@ -223,6 +226,7 @@ func TestBlockJsonMarshal(t *testing.T) {
func TestSignatureData(t *testing.T) {
tf.UnitTest(t)
newAddress := vmaddr.NewForTestGetter()
posts := []blk.PoStProof{blk.NewPoStProof(constants.DevRegisteredPoStProof, []byte{0x07})}

b := &blk.Block{
Miner: newAddress(),
Expand All @@ -242,12 +246,15 @@ func TestSignatureData(t *testing.T) {
ForkSignaling: 3,
StateRoot: e.NewCid(types.CidFromString(t, "somecid")),
Timestamp: 1,
PoStProofs: posts,
BlockSig: &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: []byte{0x3},
},
}

diffPoSts := []blk.PoStProof{blk.NewPoStProof(constants.DevRegisteredPoStProof, []byte{0x17})}

diff := &blk.Block{
Miner: newAddress(),
Ticket: blk.Ticket{VRFProof: []byte{0x03, 0x01, 0x02}},
Expand All @@ -266,6 +273,7 @@ func TestSignatureData(t *testing.T) {
ForkSignaling: 2,
StateRoot: e.NewCid(types.CidFromString(t, "someothercid")),
Timestamp: 4,
PoStProofs: diffPoSts,
BlockSig: &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: []byte{0x4},
Expand Down Expand Up @@ -408,6 +416,17 @@ func TestSignatureData(t *testing.T) {
assert.False(t, bytes.Equal(before, after))
}()

func() {
before := b.SignatureData()

cpy := b.PoStProofs
defer func() { b.PoStProofs = cpy }()

b.PoStProofs = diff.PoStProofs
after := b.SignatureData()
assert.False(t, bytes.Equal(before, after))
}()

func() {
before := b.SignatureData()
cpy := b.DrandEntries
Expand Down
52 changes: 8 additions & 44 deletions internal/pkg/block/epost_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,27 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi"
)

// EPoStCandidate wraps the input data needed to verify an election PoSt
type EPoStCandidate struct {
_ struct{} `cbor:",toarray"`
PartialTicket abi.PartialTicket
SectorID abi.SectorNumber
SectorChallengeIndex int64
}

type EPoStProof struct {
// PoStProof is a winning post proof included in a block header
type PoStProof struct {
_ struct{} `cbor:",toarray"`
RegisteredProof abi.RegisteredProof
ProofBytes []byte
}

// NewEPoStCandidate constructs an epost candidate from data
func NewEPoStCandidate(sID uint64, pt []byte, sci int64) EPoStCandidate {
return EPoStCandidate{
SectorID: abi.SectorNumber(sID),
PartialTicket: pt,
SectorChallengeIndex: sci,
}
}

// NewEPoStProof constructs an epost proof from registered proof and bytes
func NewEPoStProof(rpp abi.RegisteredProof, bs []byte) EPoStProof {
return EPoStProof{
// NewPoStProof constructs an epost proof from registered proof and bytes
func NewPoStProof(rpp abi.RegisteredProof, bs []byte) PoStProof {
return PoStProof{
RegisteredProof: rpp,
ProofBytes: bs,
}
}

// FromFFICandidate converts a Candidate to an EPoStCandidate
func FromFFICandidate(candidate abi.PoStCandidate) EPoStCandidate {
return EPoStCandidate{
PartialTicket: candidate.PartialTicket[:],
SectorID: candidate.SectorID.Number,
SectorChallengeIndex: candidate.ChallengeIndex,
}
}

// FromFFICandidates converts a variable number of Candidate to a slice of
// EPoStCandidate
func FromFFICandidates(candidates ...abi.PoStCandidate) []EPoStCandidate {
out := make([]EPoStCandidate, len(candidates))
for idx, c := range candidates {
out[idx] = FromFFICandidate(c)
}

return out
}

// FromABIPoStProofs converts the abi post proof type to a local type for
// serialization purposes
func FromABIPoStProofs(postProofs ...abi.PoStProof) []EPoStProof {
out := make([]EPoStProof, len(postProofs))
func FromABIPoStProofs(postProofs ...abi.PoStProof) []PoStProof {
out := make([]PoStProof, len(postProofs))
for i, p := range postProofs {
out[i] = EPoStProof{RegisteredProof: p.RegisteredProof, ProofBytes: p.ProofBytes}
out[i] = PoStProof{RegisteredProof: p.RegisteredProof, ProofBytes: p.ProofBytes}
}

return out
Expand Down
131 changes: 58 additions & 73 deletions internal/pkg/consensus/election.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"math/big"

address "github.com/filecoin-project/go-address"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
acrypto "github.com/filecoin-project/specs-actors/actors/crypto"

"github.com/minio/blake2b-simd"
"github.com/pkg/errors"

Expand All @@ -26,12 +26,10 @@ type EPoStVerifier interface {
}

// ElectionMachine generates and validates PoSt partial tickets and PoSt proofs.
type ElectionMachine struct {
chain ChainRandomness
}
type ElectionMachine struct{}

func NewElectionMachine(chain ChainRandomness) *ElectionMachine {
return &ElectionMachine{chain: chain}
return &ElectionMachine{}
}

func (em ElectionMachine) GenerateElectionProof(ctx context.Context, entry *drand.Entry,
Expand All @@ -47,47 +45,29 @@ func (em ElectionMachine) GenerateElectionProof(ctx context.Context, entry *dran
return vrfProof.Data, nil
}

// GenerateCandidates creates candidate partial tickets for consideration in
// block reward election
func (em ElectionMachine) GenerateCandidates(poStRand abi.PoStRandomness, sectorInfos []abi.SectorInfo, ep postgenerator.PoStGenerator, maddr address.Address) ([]abi.PoStCandidate, error) {
dummyFaults := []abi.SectorNumber{}
proofTypeBySectorNumber := make(map[abi.SectorNumber]abi.RegisteredProof, len(sectorInfos))
for _, s := range sectorInfos {
p, err := s.RegisteredPoStProof()
if err != nil {
return nil, err
}
proofTypeBySectorNumber[s.SectorNumber] = p
}

// GenerateWinningPoSt creates a PoSt proof over the input miner ID and sector infos.
func (em ElectionMachine) GenerateWinningPoSt(allSectorInfos []abi.SectorInfo, entry *drand.Entry, epoch abi.ChainEpoch, ep postgenerator.PoStGenerator, maddr address.Address) ([]abi.PoStProof, error) {
minerID, err := address.IDFromAddress(maddr)
if err != nil {
return nil, err
}
_ = minerID

candidatesWithTicket, err := ep.GenerateEPostCandidates(context.TODO(), abi.ActorID(minerID), sectorInfos, poStRand, dummyFaults)
seed := blake2b.Sum256(entry.Signature)
randomness, err := crypto.BlendEntropy(acrypto.DomainSeparationTag_ElectionPoStChallengeSeed, seed[:], epoch, []byte{})
if err != nil {
return nil, err
}
_ = randomness

candidates := make([]abi.PoStCandidate, len(candidatesWithTicket))
for i, candidateWithTicket := range candidatesWithTicket {
candidates[i] = candidateWithTicket.Candidate
candidates[i].RegisteredProof = proofTypeBySectorNumber[candidates[i].SectorID.Number]
candidates[i].SectorID.Miner = abi.ActorID(minerID)
}
return candidates, nil
}

// GenerateEPoSt creates a PoSt proof over the input PoSt candidates. Should
// only be called on winning candidates.
func (em ElectionMachine) GenerateEPoSt(allSectorInfos []abi.SectorInfo, challengeSeed abi.PoStRandomness, winners []abi.PoStCandidate, ep postgenerator.PoStGenerator, maddr address.Address) ([]abi.PoStProof, error) {
minerID, err := address.IDFromAddress(maddr)
if err != nil {
return nil, err
}
// challengeIndexes, err := ep.GenerateWinningPoStSectorChallenge(proofs[0].RegisteredProof, minerID, randomness, len(allPrivateSectorInfos))
// if err != nil {
// return nil, err
// }
// challengedSectorInfos := filterSectorInfosByIndex(allSectorInfos, challengeIndexes)
// return ep.GenerateWinningPoSt(minerID, challengedSectorInfos, randomness)

return ep.ComputeElectionPoSt(context.TODO(), abi.ActorID(minerID), allSectorInfos, challengeSeed, winners)
return nil, nil
}

func (em ElectionMachine) VerifyElectionProof(ctx context.Context, entry *drand.Entry, epoch abi.ChainEpoch, miner address.Address, workerSigner address.Address, vrfProof crypto.VRFPi) error {
Expand All @@ -113,39 +93,31 @@ func (em ElectionMachine) IsWinner(challengeTicket []byte, sectorNum, networkPow
return lhs.Cmp(rhs) == -1
}

// VerifyPoSt verifies a PoSt proof.
func (em ElectionMachine) VerifyPoSt(ctx context.Context, ep EPoStVerifier, allSectorInfos []abi.SectorInfo, challengeSeed abi.PoStRandomness, proofs []block.EPoStProof, candidates []block.EPoStCandidate, mIDAddr address.Address) (bool, error) {
// filter down sector infos to only those referenced by candidates
// TODO: pass an actual faults count to this challenge count. https://github.com/filecoin-project/go-filecoin/issues/3875
challengeCount := ffiwrapper.ElectionPostChallengeCount(uint64(len(allSectorInfos)), 0)
minerID, err := address.IDFromAddress(mIDAddr)
// VerifyWinningPoSt verifies a Winning PoSt proof.
func (em ElectionMachine) VerifyWinningPoSt(ctx context.Context, ep EPoStVerifier, allSectorInfos []abi.SectorInfo, entry *drand.Entry, epoch abi.ChainEpoch, proofs []block.PoStProof, mIDAddr address.Address) (bool, error) {
if len(proofs) == 0 {
return false, nil
}

seed := blake2b.Sum256(entry.Signature)
randomness, err := crypto.BlendEntropy(acrypto.DomainSeparationTag_ElectionPoStChallengeSeed, seed[:], epoch, []byte{})
if err != nil {
return false, err
}
_ = randomness

sectorNumToRegisteredProof := make(map[abi.SectorNumber]abi.RegisteredProof)
for _, si := range allSectorInfos {
rpp, err := si.RegisteredPoStProof()
if err != nil {
return false, err
}
sectorNumToRegisteredProof[si.SectorNumber] = rpp
minerID, err := address.IDFromAddress(mIDAddr)
if err != nil {
return false, err
}
_ = minerID

// map inputs to abi.PoStVerifyInfo
var ffiCandidates []abi.PoStCandidate
for _, candidate := range candidates {
c := abi.PoStCandidate{
RegisteredProof: sectorNumToRegisteredProof[candidate.SectorID],
PartialTicket: candidate.PartialTicket,
SectorID: abi.SectorID{
Miner: abi.ActorID(minerID),
Number: candidate.SectorID,
},
ChallengeIndex: candidate.SectorChallengeIndex,
}
ffiCandidates = append(ffiCandidates, c)
}
// Gather sector inputs for each proof
// challengeIndexes, err := ep.GenerateWinningPoStSectorChallenge(proofs[0].RegisteredProof, minerID, randomness, len(allSectorInfos))
// if err != nil {
// return false, nil
// }
// challengedSectorsInfos := filterSectorInfosByIndex(allSectorInfos, challengeIndexes)

proofsPrime := make([]abi.PoStProof, len(proofs))
for idx := range proofsPrime {
Expand All @@ -155,16 +127,14 @@ func (em ElectionMachine) VerifyPoSt(ctx context.Context, ep EPoStVerifier, allS
}
}

poStVerifyInfo := abi.PoStVerifyInfo{
Randomness: challengeSeed,
Candidates: ffiCandidates,
Proofs: proofsPrime,
EligibleSectors: allSectorInfos,
Prover: abi.ActorID(minerID),
ChallengeCount: challengeCount,
}

return ep.VerifyElectionPost(ctx, poStVerifyInfo)
return true, nil
// verifyInfo := abi.WinningPoStVerifyInfo{
// Randomness: randomness,
// Proofs: proofsPrime,
// EligibleSectors: challengedSectorInfos,
// Prover: abi.ActorID(minerID),
// }
// return ep.VerifyWinningPost(ctx, poStVerifyInfo)
}

// TicketMachine uses a VRF and VDF to generate deterministic, unpredictable
Expand Down Expand Up @@ -220,3 +190,18 @@ func electionVRFRandomness(entry *drand.Entry, miner address.Address, epoch abi.
seed := blake2b.Sum256(entry.Signature)
return crypto.BlendEntropy(acrypto.DomainSeparationTag_ElectionPoStChallengeSeed, seed[:], epoch, entropy)
}

// func filterSectorInfosByIndex(allSectorInfos []abi.SectorInfo, challengeIDs []uint64) []abi.SectorInfo {
// idSet := make(map[uint64]struct{})
// for _, id := range challengeIDs {
// idSet[id] = struct{}{}
// }

// var filteredSectorInfos []abi.SectorInfo
// for _, si := range allSectorInfos {
// if _, ok := idSet[uint64(si.SectorNumber)]; ok {
// filteredSectorInfos = append(filteredSectorInfos, si)
// }
// }
// return filteredSectorInfos
// }
Loading

0 comments on commit 3205573

Please sign in to comment.