WIP: random beacon interface
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
		
							parent
							
								
									7e96b15091
								
							
						
					
					
						commit
						7075eaba26
					
				| @ -73,7 +73,7 @@ type FullNode interface { | ||||
| 	// miner
 | ||||
| 
 | ||||
| 	MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*MiningBaseInfo, error) | ||||
| 	MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) | ||||
| 	MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.BeaconEntry, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) | ||||
| 
 | ||||
| 	// // UX ?
 | ||||
| 
 | ||||
|  | ||||
| @ -88,8 +88,8 @@ type FullNodeStruct struct { | ||||
| 		MpoolGetNonce    func(context.Context, address.Address) (uint64, 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"` | ||||
| 		MinerCreateBlock func(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, abi.ChainEpoch, uint64) (*types.BlockMsg, error) `perm:"write"` | ||||
| 		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"` | ||||
| 
 | ||||
| 		WalletNew            func(context.Context, crypto.SigType) (address.Address, error)                       `perm:"write"` | ||||
| 		WalletHas            func(context.Context, address.Address) (bool, error)                                 `perm:"write"` | ||||
| @ -330,8 +330,8 @@ func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Add | ||||
| 	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, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) { | ||||
| 	return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, msgs, height, ts) | ||||
| 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) { | ||||
| 	return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, bvals, msgs, height, ts) | ||||
| } | ||||
| 
 | ||||
| func (c *FullNodeStruct) ChainHead(ctx context.Context) (*types.TipSet, error) { | ||||
|  | ||||
							
								
								
									
										125
									
								
								chain/beacon/beacon.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								chain/beacon/beacon.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| package beacon | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"encoding/binary" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/filecoin-project/lotus/chain/types" | ||||
| 	"github.com/filecoin-project/specs-actors/actors/abi" | ||||
| 	"github.com/filecoin-project/specs-actors/actors/crypto" | ||||
| 	logging "github.com/ipfs/go-log" | ||||
| 	"golang.org/x/xerrors" | ||||
| 
 | ||||
| 	"github.com/minio/blake2b-simd" | ||||
| ) | ||||
| 
 | ||||
| var log = logging.Logger("beacon") | ||||
| 
 | ||||
| type Response struct { | ||||
| 	Entry *types.BeaconEntry | ||||
| 	Err   error | ||||
| } | ||||
| 
 | ||||
| type DrandBeacon interface { | ||||
| 	RoundTime() time.Duration | ||||
| 	LastEntry() (*types.BeaconEntry, error) | ||||
| 	Entry(context.Context, uint64) <-chan Response | ||||
| 	VerifyEntry(*types.BeaconEntry) (bool, error) | ||||
| 	BeaconIndexesForEpoch(abi.ChainEpoch, int) []uint64 | ||||
| } | ||||
| 
 | ||||
| func ValidateBlockValues(b DrandBeacon, h *types.BlockHeader, nulls int) error { | ||||
| 	indexes := b.BeaconIndexesForEpoch(h.Height, nulls) | ||||
| 
 | ||||
| 	if len(h.BeaconEntries) != len(indexes) { | ||||
| 		return xerrors.Errorf("incorrect number of beacon entries, exp:%d got:%d", len(indexes), len(h.BeaconEntries)) | ||||
| 	} | ||||
| 
 | ||||
| 	for i, ix := range indexes { | ||||
| 		if h.BeaconEntries[i].Index != ix { | ||||
| 			return xerrors.Errorf("beacon entry at [%d] had wrong index, exp:%d got:%d", i, ix, h.BeaconEntries[i].Index) | ||||
| 		} | ||||
| 		if ok, err := b.VerifyEntry(h.BeaconEntries[i]); err != nil { | ||||
| 			return xerrors.Errorf("failed to verify beacon entry %d: %w", i, err) | ||||
| 		} else if !ok { | ||||
| 			return xerrors.Errorf("beacon entry %d was invalid", i) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func BeaconEntriesForBlock(ctx context.Context, beacon DrandBeacon, round abi.ChainEpoch, nulls int) ([]*types.BeaconEntry, error) { | ||||
| 	start := time.Now() | ||||
| 
 | ||||
| 	var out []*types.BeaconEntry | ||||
| 	for _, ei := range beacon.BeaconIndexesForEpoch(round, nulls) { | ||||
| 		rch := beacon.Entry(ctx, ei) | ||||
| 		select { | ||||
| 		case resp := <-rch: | ||||
| 			if resp.Err != nil { | ||||
| 				return nil, xerrors.Errorf("beacon entry request returned error: %w", resp.Err) | ||||
| 			} | ||||
| 
 | ||||
| 			out = append(out, resp.Entry) | ||||
| 		case <-ctx.Done(): | ||||
| 			return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for round %d: %w", round, ctx.Err()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	log.Debugw("fetching beacon entries", "took", time.Since(start), "numEntries", len(out)) | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| type mockBeacon struct { | ||||
| 	interval time.Duration | ||||
| } | ||||
| 
 | ||||
| func NewMockBeacon(interval time.Duration) *mockBeacon { | ||||
| 	mb := &mockBeacon{interval: interval} | ||||
| 
 | ||||
| 	return mb | ||||
| } | ||||
| 
 | ||||
| func (mb *mockBeacon) RoundTime() time.Duration { | ||||
| 	return mb.interval | ||||
| } | ||||
| 
 | ||||
| func (mb *mockBeacon) LastEntry() (*types.BeaconEntry, error) { | ||||
| 	panic("NYI") | ||||
| } | ||||
| 
 | ||||
| func (mb *mockBeacon) entryForIndex(index uint64) *types.BeaconEntry { | ||||
| 	buf := make([]byte, 8) | ||||
| 	binary.BigEndian.PutUint64(buf, index) | ||||
| 	rval := blake2b.Sum256(buf) | ||||
| 	return &types.BeaconEntry{ | ||||
| 		Index:     index, | ||||
| 		Signature: crypto.Signature{Type: crypto.SigTypeBLS, Data: rval[:]}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (mb *mockBeacon) Entry(ctx context.Context, index uint64) <-chan Response { | ||||
| 	e := mb.entryForIndex(index) | ||||
| 	out := make(chan Response, 1) | ||||
| 	out <- Response{Entry: e} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (mb *mockBeacon) VerifyEntry(e *types.BeaconEntry) (bool, error) { | ||||
| 	oe := mb.entryForIndex(e.Index) | ||||
| 	return bytes.Equal(e.Signature.Data, oe.Signature.Data), nil | ||||
| } | ||||
| 
 | ||||
| func (mb *mockBeacon) BeaconIndexesForEpoch(epoch abi.ChainEpoch, nulls int) []uint64 { | ||||
| 	var out []uint64 | ||||
| 	for i := nulls; i > 0; i-- { | ||||
| 		out = append(out, uint64(epoch)-uint64(i)) | ||||
| 	} | ||||
| 	out = append(out, uint64(epoch)) | ||||
| 	return []uint64{uint64(epoch)} | ||||
| } | ||||
| 
 | ||||
| var _ DrandBeacon = (*mockBeacon)(nil) | ||||
| @ -6,6 +6,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/filecoin-project/go-address" | ||||
| 	commcid "github.com/filecoin-project/go-fil-commcid" | ||||
| @ -27,6 +28,7 @@ import ( | ||||
| 
 | ||||
| 	"github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/build" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" | ||||
| 	"github.com/filecoin-project/lotus/chain/stmgr" | ||||
| 	"github.com/filecoin-project/lotus/chain/store" | ||||
| @ -51,6 +53,8 @@ type ChainGen struct { | ||||
| 
 | ||||
| 	cs *store.ChainStore | ||||
| 
 | ||||
| 	beacon beacon.DrandBeacon | ||||
| 
 | ||||
| 	sm *stmgr.StateManager | ||||
| 
 | ||||
| 	genesis   *types.BlockHeader | ||||
| @ -211,12 +215,15 @@ func NewGenerator() (*ChainGen, error) { | ||||
| 
 | ||||
| 	miners := []address.Address{maddr1, maddr2} | ||||
| 
 | ||||
| 	beac := beacon.NewMockBeacon(time.Second) | ||||
| 
 | ||||
| 	gen := &ChainGen{ | ||||
| 		bs:           bs, | ||||
| 		cs:           cs, | ||||
| 		sm:           sm, | ||||
| 		msgsPerBlock: msgsPerBlock, | ||||
| 		genesis:      genb.Genesis, | ||||
| 		beacon:       beac, | ||||
| 		w:            w, | ||||
| 
 | ||||
| 		GetMessages: getRandomMessages, | ||||
| @ -346,7 +353,13 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad | ||||
| 			} | ||||
| 
 | ||||
| 			if proof != nil { | ||||
| 				fblk, err := cg.makeBlock(base, m, proof, t, abi.ChainEpoch(round), msgs) | ||||
| 				nulls := int(round) - int(base.Height()+1) | ||||
| 				bvals, err := beacon.BeaconEntriesForBlock(context.TODO(), cg.beacon, abi.ChainEpoch(round), nulls) | ||||
| 				if err != nil { | ||||
| 					return nil, xerrors.Errorf("failed to get beacon entries: %w", err) | ||||
| 				} | ||||
| 
 | ||||
| 				fblk, err := cg.makeBlock(base, m, proof, t, bvals, abi.ChainEpoch(round), msgs) | ||||
| 				if err != nil { | ||||
| 					return nil, xerrors.Errorf("making a block for next tipset failed: %w", err) | ||||
| 				} | ||||
| @ -368,7 +381,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof *types.EPostProof, ticket *types.Ticket, height abi.ChainEpoch, msgs []*types.SignedMessage) (*types.FullBlock, error) { | ||||
| 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) { | ||||
| 
 | ||||
| 	var ts uint64 | ||||
| 	if cg.Timestamper != nil { | ||||
| @ -377,7 +390,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof * | ||||
| 		ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay) | ||||
| 	} | ||||
| 
 | ||||
| 	fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, ticket, eproof, msgs, height, ts) | ||||
| 	fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, ticket, eproof, bvals, msgs, height, ts) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -20,7 +20,7 @@ import ( | ||||
| 	"github.com/filecoin-project/lotus/chain/wallet" | ||||
| ) | ||||
| 
 | ||||
| func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, miner address.Address, parents *types.TipSet, ticket *types.Ticket, proof *types.EPostProof, msgs []*types.SignedMessage, height abi.ChainEpoch, timestamp uint64) (*types.FullBlock, error) { | ||||
| 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, msgs []*types.SignedMessage, height abi.ChainEpoch, timestamp uint64) (*types.FullBlock, error) { | ||||
| 	st, recpts, err := sm.TipSetState(ctx, parents) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("failed to load tipset state: %w", err) | ||||
| @ -35,6 +35,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal | ||||
| 		Miner:                 miner, | ||||
| 		Parents:               parents.Cids(), | ||||
| 		Ticket:                ticket, | ||||
| 		BeaconEntries:         bvals, | ||||
| 		Height:                height, | ||||
| 		Timestamp:             timestamp, | ||||
| 		EPostProof:            *proof, | ||||
|  | ||||
| @ -36,6 +36,7 @@ import ( | ||||
| 
 | ||||
| 	"github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/build" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/blocksync" | ||||
| 	"github.com/filecoin-project/lotus/chain/gen" | ||||
| 	"github.com/filecoin-project/lotus/chain/state" | ||||
| @ -55,6 +56,9 @@ type Syncer struct { | ||||
| 	// The interface for accessing and putting tipsets into local storage
 | ||||
| 	store *store.ChainStore | ||||
| 
 | ||||
| 	// handle to the random beacon for verification
 | ||||
| 	beacon beacon.DrandBeacon | ||||
| 
 | ||||
| 	// the state manager handles making state queries
 | ||||
| 	sm *stmgr.StateManager | ||||
| 
 | ||||
| @ -78,7 +82,7 @@ type Syncer struct { | ||||
| 	receiptTracker *blockReceiptTracker | ||||
| } | ||||
| 
 | ||||
| func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID) (*Syncer, error) { | ||||
| func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.DrandBeacon) (*Syncer, error) { | ||||
| 	gen, err := sm.ChainStore().GetGenesis() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @ -90,6 +94,7 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm | ||||
| 	} | ||||
| 
 | ||||
| 	s := &Syncer{ | ||||
| 		beacon:         beacon, | ||||
| 		bad:            NewBadBlockCache(), | ||||
| 		Genesis:        gent, | ||||
| 		Bsync:          bsync, | ||||
| @ -506,6 +511,8 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err | ||||
| 		return xerrors.Errorf("load parent tipset failed (%s): %w", h.Parents, err) | ||||
| 	} | ||||
| 
 | ||||
| 	nulls := h.Height - (baseTs.Height() + 1) | ||||
| 
 | ||||
| 	// fast checks first
 | ||||
| 	if h.BlockSig == nil { | ||||
| 		return xerrors.Errorf("block had nil signature") | ||||
| @ -617,6 +624,13 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err | ||||
| 		return nil | ||||
| 	}) | ||||
| 
 | ||||
| 	beaconValuesCheck := async.Err(func() error { | ||||
| 		if err := beacon.ValidateBlockValues(syncer.beacon, h, int(nulls)); err != nil { | ||||
| 			return xerrors.Errorf("failed to validate blocks random beacon values: %w", err) | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
| 
 | ||||
| 	tktsCheck := async.Err(func() error { | ||||
| 		buf := new(bytes.Buffer) | ||||
| 		if err := h.Miner.MarshalCBOR(buf); err != nil { | ||||
| @ -645,6 +659,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err | ||||
| 		minerCheck, | ||||
| 		tktsCheck, | ||||
| 		blockSigCheck, | ||||
| 		beaconValuesCheck, | ||||
| 		eproofCheck, | ||||
| 		winnerCheck, | ||||
| 		msgsCheck, | ||||
|  | ||||
| @ -34,6 +34,11 @@ type EPostProof struct { | ||||
| 	Candidates []EPostTicket | ||||
| } | ||||
| 
 | ||||
| type BeaconEntry struct { | ||||
| 	Index     uint64 | ||||
| 	Signature crypto.Signature | ||||
| } | ||||
| 
 | ||||
| type BlockHeader struct { | ||||
| 	Miner address.Address // 0
 | ||||
| 
 | ||||
| @ -41,6 +46,8 @@ type BlockHeader struct { | ||||
| 
 | ||||
| 	EPostProof EPostProof // 2
 | ||||
| 
 | ||||
| 	BeaconEntries []*BeaconEntry | ||||
| 
 | ||||
| 	Parents []cid.Cid // 3
 | ||||
| 
 | ||||
| 	ParentWeight BigInt // 4
 | ||||
|  | ||||
| @ -21,7 +21,7 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error { | ||||
| 		_, err := w.Write(cbg.CborNull) | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write([]byte{141}); err != nil { | ||||
| 	if _, err := w.Write([]byte{142}); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| @ -40,6 +40,20 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// t.BeaconEntries ([]*types.BeaconEntry) (slice)
 | ||||
| 	if len(t.BeaconEntries) > cbg.MaxLength { | ||||
| 		return xerrors.Errorf("Slice value in field t.BeaconEntries was too long") | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.BeaconEntries)))); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, v := range t.BeaconEntries { | ||||
| 		if err := v.MarshalCBOR(w); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// t.Parents ([]cid.Cid) (slice)
 | ||||
| 	if len(t.Parents) > cbg.MaxLength { | ||||
| 		return xerrors.Errorf("Slice value in field t.Parents was too long") | ||||
| @ -124,7 +138,7 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error { | ||||
| 		return fmt.Errorf("cbor input should be of type array") | ||||
| 	} | ||||
| 
 | ||||
| 	if extra != 13 { | ||||
| 	if extra != 14 { | ||||
| 		return fmt.Errorf("cbor input had wrong number of fields") | ||||
| 	} | ||||
| 
 | ||||
| @ -167,6 +181,33 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error { | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 	// t.BeaconEntries ([]*types.BeaconEntry) (slice)
 | ||||
| 
 | ||||
| 	maj, extra, err = cbg.CborReadHeader(br) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if extra > cbg.MaxLength { | ||||
| 		return fmt.Errorf("t.BeaconEntries: array too large (%d)", extra) | ||||
| 	} | ||||
| 
 | ||||
| 	if maj != cbg.MajArray { | ||||
| 		return fmt.Errorf("expected cbor array") | ||||
| 	} | ||||
| 	if extra > 0 { | ||||
| 		t.BeaconEntries = make([]*BeaconEntry, extra) | ||||
| 	} | ||||
| 	for i := 0; i < int(extra); i++ { | ||||
| 
 | ||||
| 		var v BeaconEntry | ||||
| 		if err := v.UnmarshalCBOR(br); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		t.BeaconEntries[i] = &v | ||||
| 	} | ||||
| 
 | ||||
| 	// t.Parents ([]cid.Cid) (slice)
 | ||||
| 
 | ||||
| 	maj, extra, err = cbg.CborReadHeader(br) | ||||
| @ -1455,3 +1496,66 @@ func (t *ExpTipSet) UnmarshalCBOR(r io.Reader) error { | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (t *BeaconEntry) MarshalCBOR(w io.Writer) error { | ||||
| 	if t == nil { | ||||
| 		_, err := w.Write(cbg.CborNull) | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write([]byte{130}); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// t.Index (uint64) (uint64)
 | ||||
| 
 | ||||
| 	if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Index))); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// t.Signature (crypto.Signature) (struct)
 | ||||
| 	if err := t.Signature.MarshalCBOR(w); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (t *BeaconEntry) 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 != 2 { | ||||
| 		return fmt.Errorf("cbor input had wrong number of fields") | ||||
| 	} | ||||
| 
 | ||||
| 	// t.Index (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.Index = uint64(extra) | ||||
| 
 | ||||
| 	} | ||||
| 	// t.Signature (crypto.Signature) (struct)
 | ||||
| 
 | ||||
| 	{ | ||||
| 
 | ||||
| 		if err := t.Signature.UnmarshalCBOR(br); err != nil { | ||||
| 			return xerrors.Errorf("unmarshaling t.Signature: %w", err) | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -11,6 +11,7 @@ import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/docker/go-units" | ||||
| 	"github.com/google/uuid" | ||||
| @ -37,6 +38,7 @@ import ( | ||||
| 	lapi "github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/build" | ||||
| 	"github.com/filecoin-project/lotus/chain/actors" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/types" | ||||
| 	lcli "github.com/filecoin-project/lotus/cli" | ||||
| 	"github.com/filecoin-project/lotus/genesis" | ||||
| @ -435,7 +437,9 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode, | ||||
| 			} | ||||
| 			epp := storage.NewElectionPoStProver(smgr, dtypes.MinerID(mid)) | ||||
| 
 | ||||
| 			m := miner.NewMiner(api, epp) | ||||
| 			beacon := beacon.NewMockBeacon(build.BlockDelay * time.Second) | ||||
| 
 | ||||
| 			m := miner.NewMiner(api, epp, beacon) | ||||
| 			{ | ||||
| 				if err := m.Register(a); err != nil { | ||||
| 					return xerrors.Errorf("failed to start up genesis miner: %w", err) | ||||
|  | ||||
							
								
								
									
										2
									
								
								extern/filecoin-ffi
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
								
							
						
						
									
										2
									
								
								extern/filecoin-ffi
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit 0a1990fdd9a08b122cf97b373413b688d5b429cf | ||||
| Subproject commit e899cc1dd0720e0a4d25b0e751b84e3733cbedc5 | ||||
| @ -27,6 +27,7 @@ func main() { | ||||
| 		types.MessageReceipt{}, | ||||
| 		types.BlockMsg{}, | ||||
| 		types.ExpTipSet{}, | ||||
| 		types.BeaconEntry{}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
|  | ||||
| @ -14,6 +14,7 @@ import ( | ||||
| 
 | ||||
| 	"github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/build" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/gen" | ||||
| 	"github.com/filecoin-project/lotus/chain/types" | ||||
| 
 | ||||
| @ -26,15 +27,16 @@ var log = logging.Logger("miner") | ||||
| 
 | ||||
| type waitFunc func(ctx context.Context, baseTime uint64) error | ||||
| 
 | ||||
| func NewMiner(api api.FullNode, epp gen.ElectionPoStProver) *Miner { | ||||
| func NewMiner(api api.FullNode, epp gen.ElectionPoStProver, beacon beacon.DrandBeacon) *Miner { | ||||
| 	arc, err := lru.NewARC(10000) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return &Miner{ | ||||
| 		api: api, | ||||
| 		epp: epp, | ||||
| 		api:    api, | ||||
| 		epp:    epp, | ||||
| 		beacon: beacon, | ||||
| 		waitFunc: func(ctx context.Context, baseTime uint64) error { | ||||
| 			// Wait around for half the block time in case other parents come in
 | ||||
| 			deadline := baseTime + build.PropagationDelay | ||||
| @ -49,7 +51,8 @@ func NewMiner(api api.FullNode, epp gen.ElectionPoStProver) *Miner { | ||||
| type Miner struct { | ||||
| 	api api.FullNode | ||||
| 
 | ||||
| 	epp gen.ElectionPoStProver | ||||
| 	epp    gen.ElectionPoStProver | ||||
| 	beacon beacon.DrandBeacon | ||||
| 
 | ||||
| 	lk        sync.Mutex | ||||
| 	addresses []address.Address | ||||
| @ -291,6 +294,12 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB | ||||
| 	log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.ts.Cids())) | ||||
| 	start := time.Now() | ||||
| 
 | ||||
| 	round := base.ts.Height() + base.nullRounds + 1 | ||||
| 	bvals, err := beacon.BeaconEntriesForBlock(ctx, m.beacon, round, int(base.nullRounds)) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("get beacon entries failed: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	hasPower, err := m.hasPower(ctx, addr, base.ts) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("checking if miner is slashed: %w", err) | ||||
| @ -308,7 +317,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB | ||||
| 		return nil, xerrors.Errorf("scratching ticket failed: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(base.ts.Height()+base.nullRounds+1), addr, m.epp, m.api) | ||||
| 	proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(round), addr, m.epp, m.api) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("failed to check if we win next round: %w", err) | ||||
| 	} | ||||
| @ -329,7 +338,7 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB | ||||
| 		return nil, xerrors.Errorf("computing election proof: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	b, err := m.createBlock(base, addr, ticket, proof, pending) | ||||
| 	b, err := m.createBlock(base, addr, ticket, proof, bvals, pending) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("failed to create block: %w", err) | ||||
| 	} | ||||
| @ -369,7 +378,7 @@ func (m *Miner) computeTicket(ctx context.Context, addr address.Address, base *M | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof, pending []*types.SignedMessage) (*types.BlockMsg, error) { | ||||
| func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, proof *types.EPostProof, bvals []*types.BeaconEntry, pending []*types.SignedMessage) (*types.BlockMsg, error) { | ||||
| 	msgs, err := SelectMessages(context.TODO(), m.api.StateGetActor, base.ts, pending) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("message filtering failed: %w", err) | ||||
| @ -385,7 +394,7 @@ func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *type | ||||
| 	nheight := base.ts.Height() + base.nullRounds + 1 | ||||
| 
 | ||||
| 	// 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, msgs, nheight, uint64(uts)) | ||||
| 	return m.api.MinerCreateBlock(context.TODO(), addr, base.ts.Key(), ticket, proof, bvals, msgs, nheight, uint64(uts)) | ||||
| } | ||||
| 
 | ||||
| type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) | ||||
|  | ||||
| @ -5,6 +5,7 @@ import ( | ||||
| 
 | ||||
| 	"github.com/filecoin-project/go-address" | ||||
| 	"github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/gen" | ||||
| 	lru "github.com/hashicorp/golang-lru" | ||||
| ) | ||||
| @ -16,7 +17,9 @@ func NewTestMiner(nextCh <-chan struct{}, addr address.Address) func(api.FullNod | ||||
| 			panic(err) | ||||
| 		} | ||||
| 
 | ||||
| 		beacon := beacon.NewMockBeacon(0) | ||||
| 		m := &Miner{ | ||||
| 			beacon:            beacon, | ||||
| 			api:               api, | ||||
| 			waitFunc:          chanWaiter(nextCh), | ||||
| 			epp:               epp, | ||||
|  | ||||
| @ -29,6 +29,7 @@ import ( | ||||
| 
 | ||||
| 	"github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/chain" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/blocksync" | ||||
| 	"github.com/filecoin-project/lotus/chain/gen" | ||||
| 	"github.com/filecoin-project/lotus/chain/market" | ||||
| @ -255,6 +256,7 @@ func Online() Option { | ||||
| 			Override(new(storagemarket.StorageClientNode), storageadapter.NewClientNodeAdapter), | ||||
| 			Override(RegisterClientValidatorKey, modules.RegisterClientValidator), | ||||
| 			Override(RunDealClientKey, modules.RunDealClient), | ||||
| 			Override(new(beacon.DrandBeacon), modules.RandomBeacon), | ||||
| 
 | ||||
| 			Override(new(*paychmgr.Store), paychmgr.NewStore), | ||||
| 			Override(new(*paychmgr.Manager), paychmgr.NewManager), | ||||
|  | ||||
| @ -269,13 +269,12 @@ func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, | ||||
| 	return stmgr.MinerGetBaseInfo(ctx, a.StateManager, tsk, maddr) | ||||
| } | ||||
| 
 | ||||
| // This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
 | ||||
| func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parentsTSK types.TipSetKey, ticket *types.Ticket, proof *types.EPostProof, 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.EPostProof, bvals []*types.BeaconEntry, msgs []*types.SignedMessage, height abi.ChainEpoch, ts uint64) (*types.BlockMsg, error) { | ||||
| 	parents, err := a.Chain.GetTipSetFromKey(parentsTSK) | ||||
| 	if err != nil { | ||||
| 		return nil, xerrors.Errorf("loading tipset %s: %w", parentsTSK, err) | ||||
| 	} | ||||
| 	fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, addr, parents, ticket, proof, msgs, height, ts) | ||||
| 	fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, addr, parents, ticket, proof, bvals, msgs, height, ts) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -19,6 +19,7 @@ import ( | ||||
| 	"golang.org/x/xerrors" | ||||
| 
 | ||||
| 	"github.com/filecoin-project/lotus/chain" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/blocksync" | ||||
| 	"github.com/filecoin-project/lotus/chain/messagepool" | ||||
| 	"github.com/filecoin-project/lotus/chain/stmgr" | ||||
| @ -141,8 +142,8 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, | ||||
| 	return netName, err | ||||
| } | ||||
| 
 | ||||
| func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, bsync *blocksync.BlockSync, h host.Host) (*chain.Syncer, error) { | ||||
| 	syncer, err := chain.NewSyncer(sm, bsync, h.ConnManager(), h.ID()) | ||||
| func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, bsync *blocksync.BlockSync, h host.Host, beacon beacon.DrandBeacon) (*chain.Syncer, error) { | ||||
| 	syncer, err := chain.NewSyncer(sm, bsync, h.ConnManager(), h.ID(), beacon) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -2,6 +2,8 @@ package modules | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| 
 | ||||
| 	eventbus "github.com/libp2p/go-eventbus" | ||||
| 	event "github.com/libp2p/go-libp2p-core/event" | ||||
| @ -16,6 +18,7 @@ import ( | ||||
| 	"github.com/filecoin-project/go-fil-markets/storagemarket" | ||||
| 	"github.com/filecoin-project/lotus/build" | ||||
| 	"github.com/filecoin-project/lotus/chain" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/blocksync" | ||||
| 	"github.com/filecoin-project/lotus/chain/messagepool" | ||||
| 	"github.com/filecoin-project/lotus/chain/sub" | ||||
| @ -114,3 +117,8 @@ func NewLocalDiscovery(ds dtypes.MetadataDS) *discovery.Local { | ||||
| func RetrievalResolver(l *discovery.Local) retrievalmarket.PeerResolver { | ||||
| 	return discovery.Multi(l) | ||||
| } | ||||
| 
 | ||||
| func RandomBeacon() beacon.DrandBeacon { | ||||
| 	fmt.Println("RANDOM BEACON!") | ||||
| 	return beacon.NewMockBeacon(build.BlockDelay * time.Second) | ||||
| } | ||||
|  | ||||
| @ -43,6 +43,7 @@ import ( | ||||
| 
 | ||||
| 	lapi "github.com/filecoin-project/lotus/api" | ||||
| 	"github.com/filecoin-project/lotus/build" | ||||
| 	"github.com/filecoin-project/lotus/chain/beacon" | ||||
| 	"github.com/filecoin-project/lotus/chain/gen" | ||||
| 	"github.com/filecoin-project/lotus/chain/types" | ||||
| 	"github.com/filecoin-project/lotus/markets/retrievaladapter" | ||||
| @ -257,13 +258,13 @@ func StagingGraphsync(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.Stagi | ||||
| 	return gs | ||||
| } | ||||
| 
 | ||||
| func SetupBlockProducer(lc fx.Lifecycle, ds dtypes.MetadataDS, api lapi.FullNode, epp gen.ElectionPoStProver) (*miner.Miner, error) { | ||||
| func SetupBlockProducer(lc fx.Lifecycle, ds dtypes.MetadataDS, api lapi.FullNode, epp gen.ElectionPoStProver, beacon beacon.DrandBeacon) (*miner.Miner, error) { | ||||
| 	minerAddr, err := minerAddrFromDS(ds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	m := miner.NewMiner(api, epp) | ||||
| 	m := miner.NewMiner(api, epp, beacon) | ||||
| 
 | ||||
| 	lc.Append(fx.Hook{ | ||||
| 		OnStart: func(ctx context.Context) error { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user