Implement initial mining logic
This commit is contained in:
parent
e09a379c3b
commit
d381025ccc
@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
)
|
||||
|
||||
@ -20,8 +20,9 @@ type Version struct {
|
||||
type API interface {
|
||||
// chain
|
||||
|
||||
ChainHead(context.Context) ([]cid.Cid, error)
|
||||
ChainHead(context.Context) (*chain.TipSet, error) // TODO: check serialization
|
||||
ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error // TODO: check serialization
|
||||
ChainGetRandomness(context.Context, *chain.TipSet) ([]byte, error)
|
||||
|
||||
// messages
|
||||
|
||||
@ -30,7 +31,7 @@ type API interface {
|
||||
// // status
|
||||
// // mpool
|
||||
// // // ls / show / rm
|
||||
MpoolPending(context.Context) ([]*chain.SignedMessage, error)
|
||||
MpoolPending(context.Context, *chain.TipSet) ([]*chain.SignedMessage, error)
|
||||
|
||||
// dag
|
||||
|
||||
@ -53,6 +54,8 @@ type API interface {
|
||||
// // power
|
||||
// // set-price
|
||||
// // set-perrid
|
||||
MinerStart(context.Context, address.Address) error
|
||||
MinerCreateBlock(context.Context, address.Address, *chain.TipSet, []chain.Ticket, chain.ElectionProof, []*chain.SignedMessage) (*chain.BlockMsg, error)
|
||||
|
||||
// // UX ?
|
||||
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
)
|
||||
@ -15,10 +15,14 @@ type Struct struct {
|
||||
ID func(context.Context) (peer.ID, error)
|
||||
Version func(context.Context) (Version, error)
|
||||
|
||||
ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error
|
||||
ChainHead func(context.Context) ([]cid.Cid, error)
|
||||
ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error
|
||||
ChainHead func(context.Context) (*chain.TipSet, error)
|
||||
ChainGetRandomness func(context.Context, *chain.TipSet) ([]byte, error)
|
||||
|
||||
MpoolPending func(ctx context.Context) ([]*chain.SignedMessage, error)
|
||||
MpoolPending func(context.Context, *chain.TipSet) ([]*chain.SignedMessage, error)
|
||||
|
||||
MinerStart func(context.Context, address.Address) error
|
||||
MinerCreateBlock func(context.Context, address.Address, *chain.TipSet, []chain.Ticket, chain.ElectionProof, []*chain.SignedMessage) (*chain.BlockMsg, error)
|
||||
|
||||
NetPeers func(context.Context) ([]peer.AddrInfo, error)
|
||||
NetConnect func(context.Context, peer.AddrInfo) error
|
||||
@ -26,8 +30,16 @@ type Struct struct {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Struct) MpoolPending(ctx context.Context) ([]*chain.SignedMessage, error) {
|
||||
return c.Internal.MpoolPending(ctx)
|
||||
func (c *Struct) MpoolPending(ctx context.Context, ts *chain.TipSet) ([]*chain.SignedMessage, error) {
|
||||
return c.Internal.MpoolPending(ctx, ts)
|
||||
}
|
||||
|
||||
func (c *Struct) MinerStart(ctx context.Context, addr address.Address) error {
|
||||
return c.Internal.MinerStart(ctx, addr)
|
||||
}
|
||||
|
||||
func (c *Struct) MinerCreateBlock(ctx context.Context, addr address.Address, base *chain.TipSet, tickets []chain.Ticket, eproof chain.ElectionProof, msgs []*chain.SignedMessage) (*chain.BlockMsg, error) {
|
||||
return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs)
|
||||
}
|
||||
|
||||
func (c *Struct) NetPeers(ctx context.Context) ([]peer.AddrInfo, error) {
|
||||
@ -46,10 +58,14 @@ func (c *Struct) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) erro
|
||||
return c.Internal.ChainSubmitBlock(ctx, blk)
|
||||
}
|
||||
|
||||
func (c *Struct) ChainHead(ctx context.Context) ([]cid.Cid, error) {
|
||||
func (c *Struct) ChainHead(ctx context.Context) (*chain.TipSet, error) {
|
||||
return c.Internal.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (c *Struct) ChainGetRandomness(ctx context.Context, pts *chain.TipSet) ([]byte, error) {
|
||||
return c.Internal.ChainGetRandomness(ctx, pts)
|
||||
}
|
||||
|
||||
// ID implements API.ID
|
||||
func (c *Struct) ID(ctx context.Context) (peer.ID, error) {
|
||||
return c.Internal.ID(ctx)
|
||||
|
@ -155,6 +155,8 @@ func MakeGenesisBlock(bs bstore.Blockstore, w *Wallet) (*GenesisBootstrap, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println("genesis block is: ", sb.Cid())
|
||||
|
||||
return &GenesisBootstrap{
|
||||
Genesis: b,
|
||||
MinerKey: minerAddr,
|
||||
|
149
chain/mining.go
149
chain/mining.go
@ -3,7 +3,6 @@ package chain
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
@ -14,154 +13,40 @@ import (
|
||||
bls "github.com/filecoin-project/go-lotus/lib/bls-signatures"
|
||||
)
|
||||
|
||||
type Miner struct {
|
||||
cs *ChainStore
|
||||
newBlockCB func(*FullBlock)
|
||||
|
||||
maddr address.Address
|
||||
mpool *MessagePool
|
||||
|
||||
Delay time.Duration
|
||||
|
||||
candidate *MiningBase
|
||||
}
|
||||
|
||||
func NewMiner(cs *ChainStore, maddr address.Address, mpool *MessagePool, newBlockCB func(*FullBlock)) *Miner {
|
||||
return &Miner{
|
||||
cs: cs,
|
||||
newBlockCB: newBlockCB,
|
||||
maddr: maddr,
|
||||
mpool: mpool,
|
||||
Delay: time.Second * 2,
|
||||
}
|
||||
}
|
||||
|
||||
type MiningBase struct {
|
||||
ts *TipSet
|
||||
tickets []Ticket
|
||||
}
|
||||
|
||||
func (m *Miner) Mine(ctx context.Context) {
|
||||
log.Error("mining...")
|
||||
defer log.Error("left mining...")
|
||||
for {
|
||||
base := m.GetBestMiningCandidate()
|
||||
|
||||
b, err := m.mineOne(ctx, base)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if b != nil {
|
||||
m.submitNewBlock(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Miner) GetBestMiningCandidate() *MiningBase {
|
||||
best := m.cs.GetHeaviestTipSet()
|
||||
if m.candidate == nil {
|
||||
if best == nil {
|
||||
panic("no best candidate!")
|
||||
}
|
||||
return &MiningBase{
|
||||
ts: best,
|
||||
}
|
||||
}
|
||||
|
||||
if m.cs.Weight(best) > m.cs.Weight(m.candidate.ts) {
|
||||
return &MiningBase{
|
||||
ts: best,
|
||||
}
|
||||
}
|
||||
|
||||
return m.candidate
|
||||
}
|
||||
|
||||
func (m *Miner) submitNullTicket(base *MiningBase, ticket Ticket) {
|
||||
panic("nyi")
|
||||
}
|
||||
|
||||
func (m *Miner) isWinnerNextRound(base *MiningBase) (bool, ElectionProof, error) {
|
||||
return true, []byte("election prooooof"), nil
|
||||
}
|
||||
|
||||
func (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (Ticket, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-time.After(m.Delay):
|
||||
}
|
||||
|
||||
return []byte("this is a ticket"), nil
|
||||
}
|
||||
|
||||
func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*FullBlock, error) {
|
||||
log.Info("mine one")
|
||||
ticket, err := m.scratchTicket(ctx, base)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "scratching ticket failed")
|
||||
}
|
||||
|
||||
win, proof, err := m.isWinnerNextRound(base)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to check if we win next round")
|
||||
}
|
||||
|
||||
if !win {
|
||||
m.submitNullTicket(base, ticket)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b, err := m.createBlock(base, ticket, proof)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create block")
|
||||
}
|
||||
fmt.Println("created new block:", b.Cid())
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (m *Miner) submitNewBlock(b *FullBlock) {
|
||||
if err := m.cs.AddBlock(b.Header); err != nil {
|
||||
log.Error("failed to add new block to chainstore: ", err)
|
||||
}
|
||||
m.newBlockCB(b)
|
||||
}
|
||||
|
||||
func miningRewardForBlock(base *TipSet) BigInt {
|
||||
return NewInt(10000)
|
||||
}
|
||||
|
||||
func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof) (*FullBlock, error) {
|
||||
st, err := m.cs.TipSetState(base.ts.Cids())
|
||||
func MinerCreateBlock(cs *ChainStore, miner address.Address, parents *TipSet, tickets []Ticket, proof ElectionProof, msgs []*SignedMessage) (*FullBlock, error) {
|
||||
st, err := cs.TipSetState(parents.Cids())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load tipset state")
|
||||
}
|
||||
|
||||
height := base.ts.Height() + uint64(len(base.tickets)) + 1
|
||||
height := parents.Height() + uint64(len(tickets))
|
||||
|
||||
vm, err := NewVM(st, height, m.maddr, m.cs)
|
||||
vm, err := NewVM(st, height, miner, cs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// apply miner reward
|
||||
if err := vm.TransferFunds(NetworkAddress, m.maddr, miningRewardForBlock(base.ts)); err != nil {
|
||||
if err := vm.TransferFunds(NetworkAddress, miner, miningRewardForBlock(parents)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
next := &BlockHeader{
|
||||
Miner: m.maddr,
|
||||
Parents: base.ts.Cids(),
|
||||
Tickets: append(base.tickets, ticket),
|
||||
Miner: miner,
|
||||
Parents: parents.Cids(),
|
||||
Tickets: tickets,
|
||||
Height: height,
|
||||
}
|
||||
|
||||
pending := m.mpool.Pending()
|
||||
fmt.Printf("adding %d messages to block...", len(pending))
|
||||
fmt.Printf("adding %d messages to block...", len(msgs))
|
||||
var msgCids []cid.Cid
|
||||
var blsSigs []Signature
|
||||
var receipts []interface{}
|
||||
for _, msg := range pending {
|
||||
for _, msg := range msgs {
|
||||
if msg.Signature.TypeCode() == 2 {
|
||||
blsSigs = append(blsSigs, msg.Signature)
|
||||
|
||||
@ -169,7 +54,7 @@ func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := m.cs.bs.Put(blk); err != nil {
|
||||
if err := cs.bs.Put(blk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -185,7 +70,7 @@ func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof
|
||||
receipts = append(receipts, rec)
|
||||
}
|
||||
|
||||
cst := hamt.CSTFromBstore(m.cs.bs)
|
||||
cst := hamt.CSTFromBstore(cs.bs)
|
||||
msgroot, err := sharray.Build(context.TODO(), 4, toIfArr(msgCids), cst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -210,12 +95,12 @@ func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof
|
||||
|
||||
next.BLSAggregate = aggSig
|
||||
next.StateRoot = stateRoot
|
||||
pweight := m.cs.Weight(base.ts)
|
||||
pweight := cs.Weight(parents)
|
||||
next.ParentWeight = NewInt(pweight)
|
||||
|
||||
fullBlock := &FullBlock{
|
||||
Header: next,
|
||||
Messages: pending,
|
||||
Messages: msgs,
|
||||
}
|
||||
|
||||
return fullBlock, nil
|
||||
|
@ -37,13 +37,15 @@ type Syncer struct {
|
||||
// handle to the block sync service
|
||||
Bsync *BlockSync
|
||||
|
||||
self peer.ID
|
||||
|
||||
// peer heads
|
||||
// Note: clear cache on disconnects
|
||||
peerHeads map[peer.ID]*TipSet
|
||||
peerHeadsLk sync.Mutex
|
||||
}
|
||||
|
||||
func NewSyncer(cs *ChainStore, bsync *BlockSync) (*Syncer, error) {
|
||||
func NewSyncer(cs *ChainStore, bsync *BlockSync, self peer.ID) (*Syncer, error) {
|
||||
gen, err := cs.GetGenesis()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -61,6 +63,7 @@ func NewSyncer(cs *ChainStore, bsync *BlockSync) (*Syncer, error) {
|
||||
peerHeads: make(map[peer.ID]*TipSet),
|
||||
head: cs.GetHeaviestTipSet(),
|
||||
store: cs,
|
||||
self: self,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -120,6 +123,21 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *FullTipSet) {
|
||||
if fts == nil {
|
||||
panic("bad")
|
||||
}
|
||||
if from == syncer.self {
|
||||
// TODO: this is kindof a hack...
|
||||
log.Infof("got block from ourselves")
|
||||
syncer.syncLock.Lock()
|
||||
defer syncer.syncLock.Unlock()
|
||||
|
||||
if syncer.syncMode == Bootstrap {
|
||||
syncer.syncMode = CaughtUp
|
||||
}
|
||||
if err := syncer.SyncCaughtUp(fts); err != nil {
|
||||
log.Errorf("failed to sync our own block: %s", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
syncer.peerHeadsLk.Lock()
|
||||
syncer.peerHeads[from] = fts.TipSet()
|
||||
syncer.peerHeadsLk.Unlock()
|
||||
@ -180,7 +198,25 @@ func (syncer *Syncer) SyncBootstrap() {
|
||||
|
||||
blockSet := []*TipSet{selectedHead}
|
||||
cur := selectedHead.Cids()
|
||||
for /* would be cool to have a terminating condition maybe */ {
|
||||
|
||||
// If, for some reason, we have a suffix of the chain locally, handle that here
|
||||
for blockSet[len(blockSet)-1].Height() > 0 {
|
||||
log.Errorf("syncing local: ", cur)
|
||||
ts, err := syncer.store.LoadTipSet(cur)
|
||||
if err != nil {
|
||||
if err == bstore.ErrNotFound {
|
||||
log.Error("not found: ", cur)
|
||||
break
|
||||
}
|
||||
log.Errorf("loading local tipset: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
blockSet = append(blockSet, ts)
|
||||
cur = ts.Parents()
|
||||
}
|
||||
|
||||
for blockSet[len(blockSet)-1].Height() > 0 {
|
||||
// NB: GetBlocks validates that the blocks are in-fact the ones we
|
||||
// requested, and that they are correctly linked to eachother. It does
|
||||
// not validate any state transitions
|
||||
@ -194,9 +230,6 @@ func (syncer *Syncer) SyncBootstrap() {
|
||||
for _, b := range blks {
|
||||
blockSet = append(blockSet, b)
|
||||
}
|
||||
if blks[len(blks)-1].Height() == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
cur = blks[len(blks)-1].Parents()
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ var chainHeadCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
for _, c := range head {
|
||||
for _, c := range head.Cids() {
|
||||
fmt.Println(c)
|
||||
}
|
||||
return nil
|
||||
|
@ -47,4 +47,5 @@ var Commands = []*cli.Command{
|
||||
netCmd,
|
||||
versionCmd,
|
||||
mpoolCmd,
|
||||
minerCmd,
|
||||
}
|
||||
|
41
cli/miner.go
Normal file
41
cli/miner.go
Normal file
@ -0,0 +1,41 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
)
|
||||
|
||||
var minerCmd = &cli.Command{
|
||||
Name: "miner",
|
||||
Usage: "Manage mining",
|
||||
Subcommands: []*cli.Command{
|
||||
minerStart,
|
||||
},
|
||||
}
|
||||
|
||||
var minerStart = &cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start mining",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api := getApi(cctx)
|
||||
ctx := reqContext(cctx)
|
||||
|
||||
// TODO: this address needs to be the address of an actual miner
|
||||
maddr, err := address.NewIDAddress(523423423)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create miner address")
|
||||
}
|
||||
|
||||
if err := api.MinerStart(ctx, maddr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("started mining")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
@ -21,7 +21,7 @@ var mpoolPending = &cli.Command{
|
||||
api := getApi(cctx)
|
||||
ctx := reqContext(cctx)
|
||||
|
||||
msgs, err := api.MpoolPending(ctx)
|
||||
msgs, err := api.MpoolPending(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/api"
|
||||
@ -14,6 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
logging.SetLogLevel("*", "INFO")
|
||||
local := []*cli.Command{
|
||||
daemon.Cmd,
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ var Cmd = &cli.Command{
|
||||
Name: "api",
|
||||
Value: ":1234",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "bootstrap",
|
||||
Usage: "start node as already bootstrapped. Useful when starting a new testnet",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := context.Background()
|
||||
|
@ -8,36 +8,46 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
chain "github.com/filecoin-project/go-lotus/chain"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
)
|
||||
|
||||
var log = logging.Logger("miner")
|
||||
|
||||
type api interface {
|
||||
SubmitNewBlock(blk *chain.BlockMsg) error
|
||||
ChainSubmitBlock(context.Context, *chain.BlockMsg) error
|
||||
|
||||
// returns a set of messages that havent been included in the chain as of
|
||||
// the given tipset
|
||||
PendingMessages(base *chain.TipSet) ([]*chain.SignedMessage, error)
|
||||
MpoolPending(ctx context.Context, base *chain.TipSet) ([]*chain.SignedMessage, error)
|
||||
|
||||
// Returns the best tipset for the miner to mine on top of.
|
||||
// TODO: Not sure this feels right (including the messages api). Miners
|
||||
// will likely want to have more control over exactly which blocks get
|
||||
// mined on, and which messages are included.
|
||||
GetBestTipset() (*chain.TipSet, error)
|
||||
ChainHead(context.Context) (*chain.TipSet, error)
|
||||
|
||||
// returns the lookback randomness from the chain used for the election
|
||||
GetChainRandomness(ts *chain.TipSet) ([]byte, error)
|
||||
ChainGetRandomness(context.Context, *chain.TipSet) ([]byte, error)
|
||||
|
||||
// create a block
|
||||
// it seems realllllly annoying to do all the actions necessary to build a
|
||||
// block through the API. so, we just add the block creation to the API
|
||||
// now, all the 'miner' does is check if they win, and call create block
|
||||
CreateBlock(base *chain.TipSet, tickets []chain.Ticket, eproof chain.ElectionProof, msgs []*chain.SignedMessage) (*chain.BlockMsg, error)
|
||||
MinerCreateBlock(context.Context, address.Address, *chain.TipSet, []chain.Ticket, chain.ElectionProof, []*chain.SignedMessage) (*chain.BlockMsg, error)
|
||||
}
|
||||
|
||||
func NewMiner(api api, addr address.Address) *Miner {
|
||||
return &Miner{
|
||||
api: api,
|
||||
Delay: time.Second * 4,
|
||||
}
|
||||
}
|
||||
|
||||
type Miner struct {
|
||||
api api
|
||||
|
||||
address address.Address
|
||||
|
||||
// time between blocks, network parameter
|
||||
Delay time.Duration
|
||||
|
||||
@ -59,7 +69,7 @@ func (m *Miner) Mine(ctx context.Context) {
|
||||
}
|
||||
|
||||
if b != nil {
|
||||
if err := m.api.SubmitNewBlock(b); err != nil {
|
||||
if err := m.api.ChainSubmitBlock(ctx, b); err != nil {
|
||||
log.Errorf("failed to submit newly mined block: %s", err)
|
||||
}
|
||||
}
|
||||
@ -72,7 +82,7 @@ type MiningBase struct {
|
||||
}
|
||||
|
||||
func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) {
|
||||
bts, err := m.api.GetBestTipset()
|
||||
bts, err := m.api.ChainHead(context.TODO())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -93,7 +103,7 @@ func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) {
|
||||
}
|
||||
|
||||
func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg, error) {
|
||||
log.Info("mine one")
|
||||
log.Info("mine one on:", base.ts.Cids())
|
||||
ticket, err := m.scratchTicket(ctx, base)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "scratching ticket failed")
|
||||
@ -114,6 +124,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg,
|
||||
return nil, errors.Wrap(err, "failed to create block")
|
||||
}
|
||||
log.Infof("created new block: %s", b.Cid())
|
||||
log.Infof("new blocks parents: %s", b.Header.Parents)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
@ -124,7 +135,7 @@ func (m *Miner) submitNullTicket(base *MiningBase, ticket chain.Ticket) {
|
||||
}
|
||||
|
||||
func (m *Miner) isWinnerNextRound(base *MiningBase) (bool, chain.ElectionProof, error) {
|
||||
r, err := m.api.GetChainRandomness(base.ts)
|
||||
r, err := m.api.ChainGetRandomness(context.TODO(), base.ts)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
@ -146,13 +157,15 @@ func (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (chain.Tick
|
||||
|
||||
func (m *Miner) createBlock(base *MiningBase, ticket chain.Ticket, proof chain.ElectionProof) (*chain.BlockMsg, error) {
|
||||
|
||||
pending, err := m.api.PendingMessages(base.ts)
|
||||
pending, err := m.api.MpoolPending(context.TODO(), base.ts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get pending messages")
|
||||
}
|
||||
|
||||
msgs := m.selectMessages(pending)
|
||||
|
||||
// why even return this? that api call could just submit it for us
|
||||
return m.api.CreateBlock(base.ts, append(base.tickets, ticket), proof, pending)
|
||||
return m.api.MinerCreateBlock(context.TODO(), m.address, base.ts, append(base.tickets, ticket), proof, msgs)
|
||||
}
|
||||
|
||||
func (m *Miner) selectMessages(msgs []*chain.SignedMessage) []*chain.SignedMessage {
|
||||
|
44
node/api.go
44
node/api.go
@ -6,8 +6,9 @@ import (
|
||||
"github.com/filecoin-project/go-lotus/api"
|
||||
"github.com/filecoin-project/go-lotus/build"
|
||||
"github.com/filecoin-project/go-lotus/chain"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/miner"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
@ -22,6 +23,10 @@ type API struct {
|
||||
}
|
||||
|
||||
func (a *API) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error {
|
||||
if err := a.Chain.AddBlock(blk.Header); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := blk.Serialize()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -31,8 +36,13 @@ func (a *API) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error {
|
||||
return a.PubSub.Publish("/fil/blocks", b)
|
||||
}
|
||||
|
||||
func (a *API) ChainHead(context.Context) ([]cid.Cid, error) {
|
||||
return a.Chain.GetHeaviestTipSet().Cids(), nil
|
||||
func (a *API) ChainHead(context.Context) (*chain.TipSet, error) {
|
||||
return a.Chain.GetHeaviestTipSet(), nil
|
||||
}
|
||||
|
||||
func (a *API) ChainGetRandomness(ctx context.Context, pts *chain.TipSet) ([]byte, error) {
|
||||
// TODO: this needs to look back in the chain for the right random beacon value
|
||||
return []byte("foo bar random"), nil
|
||||
}
|
||||
|
||||
func (a *API) ID(context.Context) (peer.ID, error) {
|
||||
@ -45,10 +55,36 @@ func (a *API) Version(context.Context) (api.Version, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *API) MpoolPending(context.Context) ([]*chain.SignedMessage, error) {
|
||||
func (a *API) MpoolPending(ctx context.Context, ts *chain.TipSet) ([]*chain.SignedMessage, error) {
|
||||
// TODO: need to make sure we don't return messages that were already included in the referenced chain
|
||||
// also need to accept ts == nil just fine, assume nil == chain.Head()
|
||||
return a.Mpool.Pending(), nil
|
||||
}
|
||||
|
||||
func (a *API) MinerStart(ctx context.Context, addr address.Address) error {
|
||||
// hrm...
|
||||
m := miner.NewMiner(a, addr)
|
||||
|
||||
go m.Mine(context.TODO())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *API) MinerCreateBlock(ctx context.Context, addr address.Address, parents *chain.TipSet, tickets []chain.Ticket, proof chain.ElectionProof, msgs []*chain.SignedMessage) (*chain.BlockMsg, error) {
|
||||
fblk, err := chain.MinerCreateBlock(a.Chain, addr, parents, tickets, proof, msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out chain.BlockMsg
|
||||
out.Header = fblk.Header
|
||||
for _, msg := range fblk.Messages {
|
||||
out.Messages = append(out.Messages, msg.Cid())
|
||||
}
|
||||
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func (a *API) NetPeers(context.Context) ([]peer.AddrInfo, error) {
|
||||
conns := a.Host.Network().Conns()
|
||||
out := make([]peer.AddrInfo, len(conns))
|
||||
|
@ -80,8 +80,9 @@ type Settings struct {
|
||||
// type, and must be applied in correct order
|
||||
invokes []fx.Option
|
||||
|
||||
Online bool // Online option applied
|
||||
Config bool // Config option applied
|
||||
Online bool // Online option applied
|
||||
Bootstrap bool // Start chain syncer bootstrapped
|
||||
Config bool // Config option applied
|
||||
}
|
||||
|
||||
// Override option changes constructor for a given type
|
||||
|
Loading…
Reference in New Issue
Block a user