Reintroduce correct ticket randomness alongside ElectionProof

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
Jakub Sztandera 2020-04-08 21:06:41 +02:00
parent 9a17beba9e
commit ce4978d8c3
15 changed files with 151 additions and 331 deletions

View File

@ -73,7 +73,7 @@ type FullNode interface {
// miner // miner
MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*MiningBaseInfo, error) MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*MiningBaseInfo, error)
MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []types.BeaconEntry, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.ElectionProof, []types.BeaconEntry, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error)
// // UX ? // // UX ?

View File

@ -89,7 +89,7 @@ type FullNodeStruct struct {
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"` MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
MinerGetBaseInfo func(context.Context, address.Address, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"` MinerGetBaseInfo func(context.Context, address.Address, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
MinerCreateBlock func(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []types.BeaconEntry, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) `perm:"write"` MinerCreateBlock func(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.ElectionProof, []types.BeaconEntry, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) `perm:"write"`
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"` WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"` WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
@ -330,7 +330,7 @@ func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Add
return c.Internal.MinerGetBaseInfo(ctx, maddr, tsk) return c.Internal.MinerGetBaseInfo(ctx, maddr, tsk)
} }
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base types.TipSetKey, ticket *types.Ticket, eproof *types.EPostProof, bvals []types.BeaconEntry, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) { func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base types.TipSetKey, ticket *types.Ticket, eproof *types.ElectionProof, bvals []types.BeaconEntry, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) {
return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, bvals, msgs, height, ts) return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, bvals, msgs, height, ts)
} }

View File

@ -69,7 +69,7 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
// Mining // Mining
// Epochs // Epochs
const EcRandomnessLookback = Finality const TicketRandomnessLookback = 1
// ///// // /////
// Devnet settings // Devnet settings

View File

@ -277,17 +277,16 @@ func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
return out, nil return out, nil
} }
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round abi.ChainEpoch) ([]types.BeaconEntry, *types.Ticket, error) { func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round abi.ChainEpoch) ([]types.BeaconEntry, *types.ElectionProof, *types.Ticket, error) {
mc := &mca{w: cg.w, sm: cg.sm} mc := &mca{w: cg.w, sm: cg.sm}
prev, err := cg.cs.GetLatestBeaconEntry(pts) prev, err := cg.cs.GetLatestBeaconEntry(pts)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("getLatestBeaconEntry: %w", err) return nil, nil, nil, xerrors.Errorf("getLatestBeaconEntry: %w", err)
} }
entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, abi.ChainEpoch(round), *prev) entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, abi.ChainEpoch(round), *prev)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("get beacon entries for block: %w", err) return nil, nil, nil, xerrors.Errorf("get beacon entries for block: %w", err)
} }
if len(entries) == 0 { if len(entries) == 0 {
panic("no drand") panic("no drand")
@ -298,39 +297,37 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
rbase = entries[len(entries)-1] rbase = entries[len(entries)-1]
} }
buf := new(bytes.Buffer) eproof, err := IsRoundWinner(ctx, pts, round, m, rbase, mc)
if err := m.MarshalCBOR(buf); err != nil { if err != nil {
return nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err) return nil, nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
} }
ticketRand, err := store.DrawRandomness(rbase.Data, 17, round, buf.Bytes()) buf := new(bytes.Buffer)
if err := m.MarshalCBOR(buf); err != nil {
return nil, nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
}
ticketRand, err := cg.cs.GetRandomness(ctx, pts.Cids(), crypto.DomainSeparationTag_TicketProduction,
round-build.TicketRandomnessLookback, buf.Bytes())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
st := pts.ParentState() st := pts.ParentState()
worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m) worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("get miner worker: %w", err) return nil, nil, nil, xerrors.Errorf("get miner worker: %w", err)
} }
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand) vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("compute VRF: %w", err) return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
}
tick := &types.Ticket{
VRFProof: vrfout,
} }
// TODO winning post return? // TODO winning post return?
_, err = IsRoundWinner(ctx, pts, round, m, rbase, mc)
if err != nil {
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
}
return entries, tick, nil return entries, eproof, &types.Ticket{VRFProof: vrfout}, nil
} }
type MinedTipSet struct { type MinedTipSet struct {
@ -358,7 +355,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
for round := base.Height() + 1; len(blks) == 0; round++ { for round := base.Height() + 1; len(blks) == 0; round++ {
for _, m := range miners { for _, m := range miners {
bvals, t, err := cg.nextBlockProof(context.TODO(), base, m, round) bvals, et, ticket, err := cg.nextBlockProof(context.TODO(), base, m, round)
if err != nil { if err != nil {
return nil, xerrors.Errorf("next block proof: %w", err) return nil, xerrors.Errorf("next block proof: %w", err)
} }
@ -366,9 +363,10 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
panic("no drand") panic("no drand")
} }
if t != nil { if et != nil {
// TODO: winning post proof // TODO: winning post proof
fblk, err := cg.makeBlock(base, m, nil, t, bvals, abi.ChainEpoch(round), msgs) _ = ticket
fblk, err := cg.makeBlock(base, m, ticket, et, bvals, abi.ChainEpoch(round), msgs)
if err != nil { if err != nil {
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err) return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
} }
@ -390,7 +388,9 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
}, nil }, nil
} }
func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof *types.EPostProof, ticket *types.Ticket, bvals []types.BeaconEntry, height abi.ChainEpoch, msgs []*types.SignedMessage) (*types.FullBlock, error) { func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticket *types.Ticket,
eticket *types.ElectionProof, bvals []types.BeaconEntry, height abi.ChainEpoch,
msgs []*types.SignedMessage) (*types.FullBlock, error) {
var ts uint64 var ts uint64
if cg.Timestamper != nil { if cg.Timestamper != nil {
@ -399,7 +399,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof *
ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay) ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay)
} }
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, ticket, eproof, bvals, msgs, height, ts) fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, vrfticket, eticket, bvals, msgs, height, ts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -531,37 +531,37 @@ type ProofInput struct {
} }
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch, func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
miner address.Address, brand types.BeaconEntry, a MiningCheckAPI) (bool, error) { miner address.Address, brand types.BeaconEntry, a MiningCheckAPI) (*types.ElectionProof, error) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := miner.MarshalCBOR(buf); err != nil { if err := miner.MarshalCBOR(buf); err != nil {
return false, xerrors.Errorf("failed to cbor marshal address: %w") return nil, xerrors.Errorf("failed to cbor marshal address: %w")
} }
electionRand, err := store.DrawRandomness(brand.Data, 17, round, buf.Bytes()) electionRand, err := store.DrawRandomness(brand.Data, 17, round, buf.Bytes())
if err != nil { if err != nil {
return false, xerrors.Errorf("failed to draw randomness: %w", err) return nil, xerrors.Errorf("failed to draw randomness: %w", err)
} }
mbi, err := a.MinerGetBaseInfo(ctx, miner, ts.Key()) mbi, err := a.MinerGetBaseInfo(ctx, miner, ts.Key())
if err != nil { if err != nil {
return false, xerrors.Errorf("failed to get mining base info: %w", err) return nil, xerrors.Errorf("failed to get mining base info: %w", err)
} }
vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.Worker, electionRand) vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.Worker, electionRand)
if err != nil { if err != nil {
return false, xerrors.Errorf("failed to compute VRF: %w", err) return nil, xerrors.Errorf("failed to compute VRF: %w", err)
} }
// TODO: wire in real power // TODO: wire in real power
myPower := types.BigMul(types.NewInt(uint64(len(mbi.Sectors))), types.NewInt(uint64(mbi.SectorSize))) if !types.IsTicketWinner(vrfout, mbi.MinerPower, mbi.NetworkPower) {
if !types.IsTicketWinner(vrfout, myPower, mbi.NetworkPower) { return nil, nil
return false, nil
} }
return true, nil return &types.ElectionProof{VRFProof: vrfout}, nil
} }
/*
func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (*types.EPostProof, error) { func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (*types.EPostProof, error) {
proof, err := epp.ComputeProof(ctx, pi.sectors, pi.hvrf, pi.winners) proof, err := epp.ComputeProof(ctx, pi.sectors, pi.hvrf, pi.winners)
if err != nil { if err != nil {
@ -584,6 +584,7 @@ func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (
return &ept, nil return &ept, nil
} }
*/
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error) type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)

View File

@ -254,9 +254,6 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
b := &types.BlockHeader{ b := &types.BlockHeader{
Miner: builtin.SystemActorAddr, Miner: builtin.SystemActorAddr,
Ticket: genesisticket, Ticket: genesisticket,
EPostProof: types.EPostProof{
PostRand: []byte("i guess this is kinda random"),
},
Parents: []cid.Cid{}, Parents: []cid.Cid{},
Height: 0, Height: 0,
ParentWeight: types.NewInt(0), ParentWeight: types.NewInt(0),

View File

@ -21,8 +21,10 @@ import (
) )
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, miner address.Address, func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, miner address.Address,
parents *types.TipSet, ticket *types.Ticket, proof *types.EPostProof, bvals []types.BeaconEntry, parents *types.TipSet, vrfticket *types.Ticket, eproof *types.ElectionProof,
msgs []*types.SignedMessage, height abi.ChainEpoch, timestamp uint64) (*types.FullBlock, error) { bvals []types.BeaconEntry, msgs []*types.SignedMessage, height abi.ChainEpoch,
timestamp uint64) (*types.FullBlock, error) {
st, recpts, err := sm.TipSetState(ctx, parents) st, recpts, err := sm.TipSetState(ctx, parents)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to load tipset state: %w", err) return nil, xerrors.Errorf("failed to load tipset state: %w", err)
@ -36,7 +38,9 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
next := &types.BlockHeader{ next := &types.BlockHeader{
Miner: miner, Miner: miner,
Parents: parents.Cids(), Parents: parents.Cids(),
Ticket: ticket, Ticket: vrfticket,
ElectionProof: eproof,
BeaconEntries: bvals, BeaconEntries: bvals,
Height: height, Height: height,
Timestamp: timestamp, Timestamp: timestamp,

View File

@ -314,7 +314,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
Miner: b.Miner, Miner: b.Miner,
BlsMessages: make([]types.ChainMsg, 0, len(bms)), BlsMessages: make([]types.ChainMsg, 0, len(bms)),
SecpkMessages: make([]types.ChainMsg, 0, len(sms)), SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
TicketCount: int64(len(b.EPostProof.Proofs)), TicketCount: 1, //int64(len(b.EPostProof.Proofs)), // TODO fix this
} }
for _, m := range bms { for _, m := range bms {

View File

@ -23,6 +23,7 @@ import (
"go.opencensus.io/stats" "go.opencensus.io/stats"
"go.opencensus.io/trace" "go.opencensus.io/trace"
"go.uber.org/multierr" "go.uber.org/multierr"
"go.uber.org/zap"
amt "github.com/filecoin-project/go-amt-ipld/v2" amt "github.com/filecoin-project/go-amt-ipld/v2"
@ -893,7 +894,7 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
} }
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
// log.Desugar().WithOptions(zap.AddCallerSkip(2)).Sugar().Warnw("DrawRandomness", "base", rbase, "dsep", pers, "round", round, "entropy", entropy) log.Desugar().WithOptions(zap.AddCallerSkip(2)).Sugar().Warnw("DrawRandomness", "base", rbase, "dsep", pers, "round", round, "entropy", entropy)
h := blake2b.New256() h := blake2b.New256()
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil { if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err) return nil, xerrors.Errorf("deriving randomness: %w", err)
@ -913,11 +914,9 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers cr
defer span.End() defer span.End()
span.AddAttributes(trace.Int64Attribute("round", int64(round))) span.AddAttributes(trace.Int64Attribute("round", int64(round)))
/* //defer func() {
defer func() { //log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out)
log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out) //}()
}()
*/
for { for {
nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...)) nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
if err != nil { if err != nil {

View File

@ -18,7 +18,6 @@ import (
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p-core/connmgr" "github.com/libp2p/go-libp2p-core/connmgr"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/minio/blake2b-simd"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"github.com/whyrusleeping/pubsub" "github.com/whyrusleeping/pubsub"
"go.opencensus.io/stats" "go.opencensus.io/stats"
@ -28,7 +27,6 @@ import (
bls "github.com/filecoin-project/filecoin-ffi" bls "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2" amt "github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
@ -45,7 +43,6 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/sector-storage/ffiwrapper"
) )
var log = logging.Logger("chain") var log = logging.Logger("chain")
@ -538,30 +535,6 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("block was generated too soon (h.ts:%d < base.mints:%d + BLOCK_DELAY:%d * deltaH:%d; diff %d)", h.Timestamp, baseTs.MinTimestamp(), build.BlockDelay, h.Height-baseTs.Height(), diff) return xerrors.Errorf("block was generated too soon (h.ts:%d < base.mints:%d + BLOCK_DELAY:%d * deltaH:%d; diff %d)", h.Timestamp, baseTs.MinTimestamp(), build.BlockDelay, h.Height-baseTs.Height(), diff)
} }
winnerCheck := async.Err(func() error {
slashed, err := stmgr.GetMinerSlashed(ctx, syncer.sm, baseTs, h.Miner)
if err != nil {
return xerrors.Errorf("failed to check if block miner was slashed: %w", err)
}
if slashed {
return xerrors.Errorf("received block was from slashed or invalid miner")
}
mpow, tpow, err := stmgr.GetPower(ctx, syncer.sm, baseTs, h.Miner)
if err != nil {
return xerrors.Errorf("failed getting power: %w", err)
}
if !types.IsTicketWinner(h.Ticket.VRFProof, mpow, tpow) {
return xerrors.Errorf("miner created a block but was not a winner")
}
// TODO: validate winning post proof
return nil
})
msgsCheck := async.Err(func() error { msgsCheck := async.Err(func() error {
if err := syncer.checkBlockMessages(ctx, b, baseTs); err != nil { if err := syncer.checkBlockMessages(ctx, b, baseTs); err != nil {
return xerrors.Errorf("block had invalid messages: %w", err) return xerrors.Errorf("block had invalid messages: %w", err)
@ -606,6 +579,50 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err) return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
} }
winnerCheck := async.Err(func() error {
rBeacon := *prevBeacon
if len(h.BeaconEntries) != 0 {
rBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
}
buf := new(bytes.Buffer)
if err := h.Miner.MarshalCBOR(buf); err != nil {
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
}
//TODO: DST from spec actors when it is there
vrfBase, err := store.DrawRandomness(rBeacon.Data, 17, h.Height, buf.Bytes())
if err != nil {
return xerrors.Errorf("could not draw randomness: %w", err)
}
err = gen.VerifyVRF(ctx, waddr, vrfBase, h.ElectionProof.VRFProof)
if err != nil {
return xerrors.Errorf("validating block election proof failed: %w", err)
}
slashed, err := stmgr.GetMinerSlashed(ctx, syncer.sm, baseTs, h.Miner)
if err != nil {
return xerrors.Errorf("failed to check if block miner was slashed: %w", err)
}
if slashed {
return xerrors.Errorf("received block was from slashed or invalid miner")
}
mpow, tpow, err := stmgr.GetPower(ctx, syncer.sm, baseTs, h.Miner)
if err != nil {
return xerrors.Errorf("failed getting power: %w", err)
}
if !types.IsTicketWinner(h.ElectionProof.VRFProof, mpow, tpow) {
return xerrors.Errorf("miner created a block but was not a winner")
}
// TODO: validate winning post proof
return nil
})
blockSigCheck := async.Err(func() error { blockSigCheck := async.Err(func() error {
if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil { if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil {
return xerrors.Errorf("check block signature failed: %w", err) return xerrors.Errorf("check block signature failed: %w", err)
@ -622,18 +639,13 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
}) })
tktsCheck := async.Err(func() error { tktsCheck := async.Err(func() error {
baseBeacon := prevBeacon
if len(h.BeaconEntries) > 0 {
baseBeacon = &h.BeaconEntries[len(h.BeaconEntries)-1]
}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := h.Miner.MarshalCBOR(buf); err != nil { if err := h.Miner.MarshalCBOR(buf); err != nil {
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err) return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
} }
// TODO: use real DST from specs actors when it lands vrfBase, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(),
vrfBase, err := store.DrawRandomness(baseBeacon.Data, 17, h.Height, buf.Bytes()) crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes())
if err != nil { if err != nil {
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err) return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
} }
@ -689,6 +701,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return merr return merr
} }
/*
func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.BlockHeader, waddr address.Address) error { func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.BlockHeader, waddr address.Address) error {
curTs, err := types.NewTipSet([]*types.BlockHeader{h}) curTs, err := types.NewTipSet([]*types.BlockHeader{h})
if err != nil { if err != nil {
@ -790,6 +803,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc
return nil return nil
} }
*/
func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error { func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error {
{ {

View File

@ -22,16 +22,8 @@ type Ticket struct {
VRFProof []byte VRFProof []byte
} }
type EPostTicket struct { type ElectionProof struct {
Partial []byte VRFProof []byte
SectorID abi.SectorNumber
ChallengeIndex uint64
}
type EPostProof struct {
Proofs []abi.PoStProof
PostRand []byte
Candidates []EPostTicket
} }
type BeaconEntry struct { type BeaconEntry struct {
@ -44,7 +36,7 @@ type BlockHeader struct {
Ticket *Ticket // 1 Ticket *Ticket // 1
EPostProof EPostProof // 2 ElectionProof *ElectionProof
BeaconEntries []BeaconEntry BeaconEntries []BeaconEntry
@ -173,7 +165,7 @@ var blocksPerEpoch = NewInt(build.BlocksPerEpoch)
const sha256bits = 256 const sha256bits = 256
func IsTicketWinner(partialTicket []byte, mypow BigInt, totpow BigInt) bool { func IsTicketWinner(vrfTicket []byte, mypow BigInt, totpow BigInt) bool {
/* /*
Need to check that Need to check that
(h(vrfout) + 1) / (max(h) + 1) <= e * myPower / totalPower (h(vrfout) + 1) / (max(h) + 1) <= e * myPower / totalPower
@ -185,7 +177,7 @@ func IsTicketWinner(partialTicket []byte, mypow BigInt, totpow BigInt) bool {
*/ */
h := sha256.Sum256(partialTicket) h := sha256.Sum256(vrfTicket)
lhs := BigFromBytes(h[:]).Int lhs := BigFromBytes(h[:]).Int
lhs = lhs.Mul(lhs, totpow.Int) lhs = lhs.Mul(lhs, totpow.Int)
@ -199,14 +191,6 @@ func IsTicketWinner(partialTicket []byte, mypow BigInt, totpow BigInt) bool {
return lhs.Cmp(rhs) < 0 return lhs.Cmp(rhs) < 0
} }
func ElectionPostChallengeCount(sectors uint64, faults uint64) uint64 {
if sectors-faults == 0 {
return 0
}
// ceil(sectors / SectorChallengeRatioDiv)
return (sectors-faults-1)/build.SectorChallengeRatioDiv + 1
}
func (t *Ticket) Equals(ot *Ticket) bool { func (t *Ticket) Equals(ot *Ticket) bool {
return bytes.Equal(t.VRFProof, ot.VRFProof) return bytes.Equal(t.VRFProof, ot.VRFProof)
} }

View File

@ -35,8 +35,8 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.EPostProof (types.EPostProof) (struct) // t.ElectionProof (types.ElectionProof) (struct)
if err := t.EPostProof.MarshalCBOR(w); err != nil { if err := t.ElectionProof.MarshalCBOR(w); err != nil {
return err return err
} }
@ -172,12 +172,24 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
} }
} }
// t.EPostProof (types.EPostProof) (struct) // t.ElectionProof (types.ElectionProof) (struct)
{ {
if err := t.EPostProof.UnmarshalCBOR(br); err != nil { pb, err := br.PeekByte()
return xerrors.Errorf("unmarshaling t.EPostProof: %w", err) 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.ElectionProof = new(ElectionProof)
if err := t.ElectionProof.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.ElectionProof pointer: %w", err)
}
} }
} }
@ -435,58 +447,30 @@ func (t *Ticket) UnmarshalCBOR(r io.Reader) error {
return nil return nil
} }
func (t *EPostProof) MarshalCBOR(w io.Writer) error { func (t *ElectionProof) MarshalCBOR(w io.Writer) error {
if t == nil { if t == nil {
_, err := w.Write(cbg.CborNull) _, err := w.Write(cbg.CborNull)
return err return err
} }
if _, err := w.Write([]byte{131}); err != nil { if _, err := w.Write([]byte{129}); err != nil {
return err return err
} }
// t.Proofs ([]abi.PoStProof) (slice) // t.VRFProof ([]uint8) (slice)
if len(t.Proofs) > cbg.MaxLength { if len(t.VRFProof) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Slice value in field t.Proofs was too long") return xerrors.Errorf("Byte array in field t.VRFProof was too long")
} }
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Proofs)))); err != nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.VRFProof)))); err != nil {
return err return err
} }
for _, v := range t.Proofs { if _, err := w.Write(t.VRFProof); err != nil {
if err := v.MarshalCBOR(w); err != nil {
return err return err
} }
}
// t.PostRand ([]uint8) (slice)
if len(t.PostRand) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.PostRand was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.PostRand)))); err != nil {
return err
}
if _, err := w.Write(t.PostRand); err != nil {
return err
}
// t.Candidates ([]types.EPostTicket) (slice)
if len(t.Candidates) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.Candidates was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Candidates)))); err != nil {
return err
}
for _, v := range t.Candidates {
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
return nil return nil
} }
func (t *EPostProof) UnmarshalCBOR(r io.Reader) error { func (t *ElectionProof) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r) br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br) maj, extra, err := cbg.CborReadHeader(br)
@ -497,38 +481,11 @@ func (t *EPostProof) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type array") return fmt.Errorf("cbor input should be of type array")
} }
if extra != 3 { if extra != 1 {
return fmt.Errorf("cbor input had wrong number of fields") return fmt.Errorf("cbor input had wrong number of fields")
} }
// t.Proofs ([]abi.PoStProof) (slice) // t.VRFProof ([]uint8) (slice)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Proofs: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Proofs = make([]abi.PoStProof, extra)
}
for i := 0; i < int(extra); i++ {
var v abi.PoStProof
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.Proofs[i] = v
}
// t.PostRand ([]uint8) (slice)
maj, extra, err = cbg.CborReadHeader(br) maj, extra, err = cbg.CborReadHeader(br)
if err != nil { if err != nil {
@ -536,141 +493,15 @@ func (t *EPostProof) UnmarshalCBOR(r io.Reader) error {
} }
if extra > cbg.ByteArrayMaxLen { if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.PostRand: byte array too large (%d)", extra) return fmt.Errorf("t.VRFProof: byte array too large (%d)", extra)
} }
if maj != cbg.MajByteString { if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array") return fmt.Errorf("expected byte array")
} }
t.PostRand = make([]byte, extra) t.VRFProof = make([]byte, extra)
if _, err := io.ReadFull(br, t.PostRand); err != nil { if _, err := io.ReadFull(br, t.VRFProof); err != nil {
return err return err
} }
// t.Candidates ([]types.EPostTicket) (slice)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Candidates: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Candidates = make([]EPostTicket, extra)
}
for i := 0; i < int(extra); i++ {
var v EPostTicket
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.Candidates[i] = v
}
return nil
}
func (t *EPostTicket) 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
}
// t.Partial ([]uint8) (slice)
if len(t.Partial) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.Partial was too long")
}
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Partial)))); err != nil {
return err
}
if _, err := w.Write(t.Partial); err != nil {
return err
}
// t.SectorID (abi.SectorNumber) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorID))); err != nil {
return err
}
// t.ChallengeIndex (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ChallengeIndex))); err != nil {
return err
}
return nil
}
func (t *EPostTicket) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r)
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.Partial ([]uint8) (slice)
maj, extra, err = cbg.CborReadHeader(br)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.Partial: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
t.Partial = make([]byte, extra)
if _, err := io.ReadFull(br, t.Partial); err != nil {
return err
}
// t.SectorID (abi.SectorNumber) (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.SectorID = abi.SectorNumber(extra)
}
// t.ChallengeIndex (uint64) (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.ChallengeIndex = uint64(extra)
}
return nil return nil
} }
@ -1506,7 +1337,7 @@ func (t *BeaconEntry) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.Index (uint64) (uint64) // t.Round (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Round))); err != nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Round))); err != nil {
return err return err
@ -1541,7 +1372,7 @@ func (t *BeaconEntry) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input had wrong number of fields") return fmt.Errorf("cbor input had wrong number of fields")
} }
// t.Index (uint64) (uint64) // t.Round (uint64) (uint64)
{ {

View File

@ -60,8 +60,8 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
return &types.BlockHeader{ return &types.BlockHeader{
Miner: addr, Miner: addr,
EPostProof: types.EPostProof{ ElectionProof: &types.ElectionProof{
Proofs: []abi.PoStProof{{ProofBytes: []byte("election post proof proof")}}, VRFProof: []byte(fmt.Sprintf("====%d=====", ticketNonce)),
}, },
Ticket: &types.Ticket{ Ticket: &types.Ticket{
VRFProof: []byte(fmt.Sprintf("====%d=====", ticketNonce)), VRFProof: []byte(fmt.Sprintf("====%d=====", ticketNonce)),

View File

@ -11,15 +11,13 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/hello" "github.com/filecoin-project/lotus/node/hello"
"github.com/filecoin-project/lotus/paychmgr" "github.com/filecoin-project/lotus/paychmgr"
sealing "github.com/filecoin-project/storage-fsm"
) )
func main() { func main() {
err := gen.WriteTupleEncodersToFile("./chain/types/cbor_gen.go", "types", err := gen.WriteTupleEncodersToFile("./chain/types/cbor_gen.go", "types",
types.BlockHeader{}, types.BlockHeader{},
types.Ticket{}, types.Ticket{},
types.EPostProof{}, types.ElectionProof{},
types.EPostTicket{},
types.Message{}, types.Message{},
types.SignedMessage{}, types.SignedMessage{},
types.MsgMeta{}, types.MsgMeta{},
@ -74,13 +72,4 @@ func main() {
os.Exit(1) os.Exit(1)
} }
err = gen.WriteMapEncodersToFile("./storage/sealing/cbor_gen.go", "sealing",
sealing.Piece{},
sealing.SectorInfo{},
sealing.Log{},
)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
} }

View File

@ -9,13 +9,13 @@ import (
address "github.com/filecoin-project/go-address" address "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
@ -355,7 +355,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB
return nil, xerrors.Errorf("failed to check if we win next round: %w", err) return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
} }
if !winner { if winner == nil {
base.nullRounds++ base.nullRounds++
return nil, nil return nil, nil
} }
@ -367,7 +367,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB
} }
// TODO: winning post proof // TODO: winning post proof
b, err := m.createBlock(base, addr, ticket, nil, bvals, pending) b, err := m.createBlock(base, addr, ticket, winner, bvals, pending)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to create block: %w", err) return nil, xerrors.Errorf("failed to create block: %w", err)
} }
@ -391,7 +391,8 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, brand *
if err := addr.MarshalCBOR(buf); err != nil { if err := addr.MarshalCBOR(buf); err != nil {
return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err)
} }
input, err := store.DrawRandomness(brand.Data, 17, (base.ts.Height() + base.nullRounds + 1), buf.Bytes()) input, err := m.api.ChainGetRandomness(ctx, base.ts.Key(), crypto.DomainSeparationTag_TicketProduction,
base.ts.Height()+base.nullRounds+1-build.TicketRandomnessLookback, buf.Bytes())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -407,7 +408,7 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, brand *
} }
func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket,
proof *types.EPostProof, bvals []types.BeaconEntry, pending []*types.SignedMessage) (*types.BlockMsg, error) { eproof *types.ElectionProof, bvals []types.BeaconEntry, pending []*types.SignedMessage) (*types.BlockMsg, error) {
msgs, err := SelectMessages(context.TODO(), m.api.StateGetActor, base.ts, pending) msgs, err := SelectMessages(context.TODO(), m.api.StateGetActor, base.ts, pending)
if err != nil { if err != nil {
return nil, xerrors.Errorf("message filtering failed: %w", err) return nil, xerrors.Errorf("message filtering failed: %w", err)
@ -423,7 +424,7 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type
nheight := base.ts.Height() + base.nullRounds + 1 nheight := base.ts.Height() + base.nullRounds + 1
// why even return this? that api call could just submit it for us // why even return this? that api call could just submit it for us
return m.api.MinerCreateBlock(context.TODO(), addr, base.ts.Key(), ticket, proof, bvals, msgs, nheight, uint64(uts)) return m.api.MinerCreateBlock(context.TODO(), addr, base.ts.Key(), ticket, eproof, bvals, msgs, nheight, uint64(uts))
} }
type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error)

View File

@ -269,7 +269,7 @@ func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address,
return stmgr.MinerGetBaseInfo(ctx, a.StateManager, tsk, maddr) return stmgr.MinerGetBaseInfo(ctx, a.StateManager, tsk, maddr)
} }
func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parentsTSK types.TipSetKey, ticket *types.Ticket, proof *types.EPostProof, bvals []types.BeaconEntry, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) { func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parentsTSK types.TipSetKey, ticket *types.Ticket, proof *types.ElectionProof, bvals []types.BeaconEntry, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) {
parents, err := a.Chain.GetTipSetFromKey(parentsTSK) parents, err := a.Chain.GetTipSetFromKey(parentsTSK)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", parentsTSK, err) return nil, xerrors.Errorf("loading tipset %s: %w", parentsTSK, err)