Merge pull request #17 from filecoin-project/feat/mining-1

Implement basic mining logic
This commit is contained in:
Whyrusleeping 2019-07-11 10:09:15 -07:00 committed by GitHub
commit 3f61488e3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 287 additions and 162 deletions

View File

@ -4,8 +4,8 @@ import (
"context" "context"
"github.com/filecoin-project/go-lotus/chain" "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" "github.com/libp2p/go-libp2p-core/peer"
) )
@ -20,8 +20,9 @@ type Version struct {
type API interface { type API interface {
// chain // 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 ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error // TODO: check serialization
ChainGetRandomness(context.Context, *chain.TipSet) ([]byte, error)
// messages // messages
@ -30,6 +31,7 @@ type API interface {
// // status // // status
// // mpool // // mpool
// // // ls / show / rm // // // ls / show / rm
MpoolPending(context.Context, *chain.TipSet) ([]*chain.SignedMessage, error)
// dag // dag
@ -52,6 +54,8 @@ type API interface {
// // power // // power
// // set-price // // set-price
// // set-perrid // // 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 ? // // UX ?

View File

@ -4,8 +4,8 @@ import (
"context" "context"
"github.com/filecoin-project/go-lotus/chain" "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" "github.com/libp2p/go-libp2p-core/peer"
) )
@ -15,8 +15,14 @@ type Struct struct {
ID func(context.Context) (peer.ID, error) ID func(context.Context) (peer.ID, error)
Version func(context.Context) (Version, error) Version func(context.Context) (Version, error)
ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error
ChainHead func(context.Context) ([]cid.Cid, error) ChainHead func(context.Context) (*chain.TipSet, error)
ChainGetRandomness func(context.Context, *chain.TipSet) ([]byte, 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) NetPeers func(context.Context) ([]peer.AddrInfo, error)
NetConnect func(context.Context, peer.AddrInfo) error NetConnect func(context.Context, peer.AddrInfo) error
@ -24,6 +30,18 @@ type Struct struct {
} }
} }
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) { func (c *Struct) NetPeers(ctx context.Context) ([]peer.AddrInfo, error) {
return c.Internal.NetPeers(ctx) return c.Internal.NetPeers(ctx)
} }
@ -40,10 +58,14 @@ func (c *Struct) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) erro
return c.Internal.ChainSubmitBlock(ctx, blk) 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) 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 // ID implements API.ID
func (c *Struct) ID(ctx context.Context) (peer.ID, error) { func (c *Struct) ID(ctx context.Context) (peer.ID, error) {
return c.Internal.ID(ctx) return c.Internal.ID(ctx)

View File

@ -226,7 +226,7 @@ func (cs *ChainStore) maybeTakeHeavierTipSet(ts *TipSet) error {
return err return err
} }
cs.headChange(revert, apply) cs.headChange(revert, apply)
log.Errorf("New heaviest tipset! %s", ts.Cids()) log.Infof("New heaviest tipset! %s", ts.Cids())
cs.heaviest = ts cs.heaviest = ts
} }
return nil return nil

View File

@ -3,7 +3,6 @@ package chain
import ( import (
"context" "context"
"fmt" "fmt"
"time"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld" hamt "github.com/ipfs/go-hamt-ipld"
@ -14,154 +13,40 @@ import (
bls "github.com/filecoin-project/go-lotus/lib/bls-signatures" 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 { func miningRewardForBlock(base *TipSet) BigInt {
return NewInt(10000) return NewInt(10000)
} }
func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof) (*FullBlock, error) { func MinerCreateBlock(cs *ChainStore, miner address.Address, parents *TipSet, tickets []Ticket, proof ElectionProof, msgs []*SignedMessage) (*FullBlock, error) {
st, err := m.cs.TipSetState(base.ts.Cids()) st, err := cs.TipSetState(parents.Cids())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to load tipset state") 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 // 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 return nil, err
} }
next := &BlockHeader{ next := &BlockHeader{
Miner: m.maddr, Miner: miner,
Parents: base.ts.Cids(), Parents: parents.Cids(),
Tickets: append(base.tickets, ticket), Tickets: tickets,
Height: height, Height: height,
} }
pending := m.mpool.Pending() fmt.Printf("adding %d messages to block...", len(msgs))
fmt.Printf("adding %d messages to block...", len(pending))
var msgCids []cid.Cid var msgCids []cid.Cid
var blsSigs []Signature var blsSigs []Signature
var receipts []interface{} var receipts []interface{}
for _, msg := range pending { for _, msg := range msgs {
if msg.Signature.TypeCode() == 2 { if msg.Signature.TypeCode() == 2 {
blsSigs = append(blsSigs, msg.Signature) blsSigs = append(blsSigs, msg.Signature)
@ -169,7 +54,7 @@ func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := m.cs.bs.Put(blk); err != nil { if err := cs.bs.Put(blk); err != nil {
return nil, err return nil, err
} }
@ -185,7 +70,7 @@ func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof
receipts = append(receipts, rec) 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) msgroot, err := sharray.Build(context.TODO(), 4, toIfArr(msgCids), cst)
if err != nil { if err != nil {
return nil, err return nil, err
@ -210,12 +95,12 @@ func (m *Miner) createBlock(base *MiningBase, ticket Ticket, proof ElectionProof
next.BLSAggregate = aggSig next.BLSAggregate = aggSig
next.StateRoot = stateRoot next.StateRoot = stateRoot
pweight := m.cs.Weight(base.ts) pweight := cs.Weight(parents)
next.ParentWeight = NewInt(pweight) next.ParentWeight = NewInt(pweight)
fullBlock := &FullBlock{ fullBlock := &FullBlock{
Header: next, Header: next,
Messages: pending, Messages: msgs,
} }
return fullBlock, nil return fullBlock, nil

View File

@ -37,13 +37,15 @@ type Syncer struct {
// handle to the block sync service // handle to the block sync service
Bsync *BlockSync Bsync *BlockSync
self peer.ID
// peer heads // peer heads
// Note: clear cache on disconnects // Note: clear cache on disconnects
peerHeads map[peer.ID]*TipSet peerHeads map[peer.ID]*TipSet
peerHeadsLk sync.Mutex 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() gen, err := cs.GetGenesis()
if err != nil { if err != nil {
return nil, err return nil, err
@ -61,6 +63,7 @@ func NewSyncer(cs *ChainStore, bsync *BlockSync) (*Syncer, error) {
peerHeads: make(map[peer.ID]*TipSet), peerHeads: make(map[peer.ID]*TipSet),
head: cs.GetHeaviestTipSet(), head: cs.GetHeaviestTipSet(),
store: cs, store: cs,
self: self,
}, nil }, nil
} }
@ -120,6 +123,21 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *FullTipSet) {
if fts == nil { if fts == nil {
panic("bad") 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.peerHeadsLk.Lock()
syncer.peerHeads[from] = fts.TipSet() syncer.peerHeads[from] = fts.TipSet()
syncer.peerHeadsLk.Unlock() syncer.peerHeadsLk.Unlock()
@ -180,7 +198,25 @@ func (syncer *Syncer) SyncBootstrap() {
blockSet := []*TipSet{selectedHead} blockSet := []*TipSet{selectedHead}
cur := selectedHead.Cids() 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 // NB: GetBlocks validates that the blocks are in-fact the ones we
// requested, and that they are correctly linked to eachother. It does // requested, and that they are correctly linked to eachother. It does
// not validate any state transitions // not validate any state transitions
@ -194,9 +230,6 @@ func (syncer *Syncer) SyncBootstrap() {
for _, b := range blks { for _, b := range blks {
blockSet = append(blockSet, b) blockSet = append(blockSet, b)
} }
if blks[len(blks)-1].Height() == 0 {
break
}
cur = blks[len(blks)-1].Parents() cur = blks[len(blks)-1].Parents()
} }

View File

@ -3,6 +3,7 @@ package chain
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json"
"fmt" "fmt"
"math/big" "math/big"
@ -229,6 +230,25 @@ func (bi *BigInt) Nil() bool {
return bi.Int == nil return bi.Int == nil
} }
func (bi *BigInt) MarshalJSON() ([]byte, error) {
return json.Marshal(bi.String())
}
func (bi *BigInt) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
i, ok := big.NewInt(0).SetString(s, 10)
if !ok {
return fmt.Errorf("failed to parse bigint string")
}
bi.Int = i
return nil
}
type Actor struct { type Actor struct {
Code cid.Cid Code cid.Cid
Head cid.Cid Head cid.Cid
@ -402,6 +422,34 @@ type TipSet struct {
height uint64 height uint64
} }
// why didnt i just export the fields? Because the struct has methods with the
// same names already
type expTipSet struct {
Cids []cid.Cid
Blocks []*BlockHeader
Height uint64
}
func (ts *TipSet) MarshalJSON() ([]byte, error) {
return json.Marshal(expTipSet{
Cids: ts.cids,
Blocks: ts.blks,
Height: ts.height,
})
}
func (ts *TipSet) UnmarshalJSON(b []byte) error {
var ets expTipSet
if err := json.Unmarshal(b, &ets); err != nil {
return err
}
ts.cids = ets.Cids
ts.blks = ets.Blocks
ts.height = ets.Height
return nil
}
func NewTipSet(blks []*BlockHeader) (*TipSet, error) { func NewTipSet(blks []*BlockHeader) (*TipSet, error) {
var ts TipSet var ts TipSet
ts.cids = []cid.Cid{blks[0].Cid()} ts.cids = []cid.Cid{blks[0].Cid()}

View File

@ -29,7 +29,7 @@ var chainHeadCmd = &cli.Command{
return err return err
} }
for _, c := range head { for _, c := range head.Cids() {
fmt.Println(c) fmt.Println(c)
} }
return nil return nil

View File

@ -62,4 +62,6 @@ var Commands = []*cli.Command{
chainCmd, chainCmd,
netCmd, netCmd,
versionCmd, versionCmd,
mpoolCmd,
minerCmd,
} }

41
cli/miner.go Normal file
View 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
},
}

35
cli/mpool.go Normal file
View File

@ -0,0 +1,35 @@
package cli
import (
"fmt"
"gopkg.in/urfave/cli.v2"
)
var mpoolCmd = &cli.Command{
Name: "mpool",
Usage: "Manage message pool",
Subcommands: []*cli.Command{
mpoolPending,
},
}
var mpoolPending = &cli.Command{
Name: "pending",
Usage: "Get pending messages",
Action: func(cctx *cli.Context) error {
api := getApi(cctx)
ctx := reqContext(cctx)
msgs, err := api.MpoolPending(ctx, nil)
if err != nil {
return err
}
for _, msg := range msgs {
fmt.Println(msg)
}
return nil
},
}

View File

@ -4,6 +4,7 @@ import (
"log" "log"
"os" "os"
logging "github.com/ipfs/go-log"
"gopkg.in/urfave/cli.v2" "gopkg.in/urfave/cli.v2"
"github.com/filecoin-project/go-lotus/build" "github.com/filecoin-project/go-lotus/build"
@ -12,6 +13,7 @@ import (
) )
func main() { func main() {
logging.SetLogLevel("*", "INFO")
local := []*cli.Command{ local := []*cli.Command{
daemon.Cmd, daemon.Cmd,
} }

View File

@ -8,36 +8,46 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
chain "github.com/filecoin-project/go-lotus/chain" chain "github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/address"
) )
var log = logging.Logger("miner") var log = logging.Logger("miner")
type api interface { 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 // returns a set of messages that havent been included in the chain as of
// the given tipset // 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. // Returns the best tipset for the miner to mine on top of.
// TODO: Not sure this feels right (including the messages api). Miners // TODO: Not sure this feels right (including the messages api). Miners
// will likely want to have more control over exactly which blocks get // will likely want to have more control over exactly which blocks get
// mined on, and which messages are included. // 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 // 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 // create a block
// it seems realllllly annoying to do all the actions necessary to build a // 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 // 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 // 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 { type Miner struct {
api api api api
address address.Address
// time between blocks, network parameter // time between blocks, network parameter
Delay time.Duration Delay time.Duration
@ -59,7 +69,7 @@ func (m *Miner) Mine(ctx context.Context) {
} }
if b != nil { 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) log.Errorf("failed to submit newly mined block: %s", err)
} }
} }
@ -72,7 +82,7 @@ type MiningBase struct {
} }
func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) { func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) {
bts, err := m.api.GetBestTipset() bts, err := m.api.ChainHead(context.TODO())
if err != nil { if err != nil {
return nil, err 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) { func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg, error) {
log.Info("mine one") log.Info("attempting to mine a block on:", base.ts.Cids())
ticket, err := m.scratchTicket(ctx, base) ticket, err := m.scratchTicket(ctx, base)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "scratching ticket failed") return nil, errors.Wrap(err, "scratching ticket failed")
@ -113,7 +123,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg,
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to create block") return nil, errors.Wrap(err, "failed to create block")
} }
log.Infof("created new block: %s", b.Cid()) log.Infof("mined new block: %s", b.Cid())
return b, nil return b, nil
} }
@ -124,7 +134,7 @@ func (m *Miner) submitNullTicket(base *MiningBase, ticket chain.Ticket) {
} }
func (m *Miner) isWinnerNextRound(base *MiningBase) (bool, chain.ElectionProof, error) { 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 { if err != nil {
return false, nil, err return false, nil, err
} }
@ -146,13 +156,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) { 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 { if err != nil {
return nil, errors.Wrapf(err, "failed to get pending messages") 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 // 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 { func (m *Miner) selectMessages(msgs []*chain.SignedMessage) []*chain.SignedMessage {

View File

@ -6,8 +6,9 @@ import (
"github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/build" "github.com/filecoin-project/go-lotus/build"
"github.com/filecoin-project/go-lotus/chain" "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/host"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
@ -18,9 +19,14 @@ type API struct {
Host host.Host Host host.Host
Chain *chain.ChainStore Chain *chain.ChainStore
PubSub *pubsub.PubSub PubSub *pubsub.PubSub
Mpool *chain.MessagePool
} }
func (a *API) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error { 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() b, err := blk.Serialize()
if err != nil { if err != nil {
return err return err
@ -30,8 +36,13 @@ func (a *API) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error {
return a.PubSub.Publish("/fil/blocks", b) return a.PubSub.Publish("/fil/blocks", b)
} }
func (a *API) ChainHead(context.Context) ([]cid.Cid, error) { func (a *API) ChainHead(context.Context) (*chain.TipSet, error) {
return a.Chain.GetHeaviestTipSet().Cids(), nil 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) { func (a *API) ID(context.Context) (peer.ID, error) {
@ -44,6 +55,36 @@ func (a *API) Version(context.Context) (api.Version, error) {
}, nil }, nil
} }
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) { func (a *API) NetPeers(context.Context) ([]peer.AddrInfo, error) {
conns := a.Host.Network().Conns() conns := a.Host.Network().Conns()
out := make([]peer.AddrInfo, len(conns)) out := make([]peer.AddrInfo, len(conns))

View File

@ -58,7 +58,7 @@ const (
StartListeningKey StartListeningKey
// filecoin // filecoin
SetGenisisKey SetGenesisKey
RunHelloKey RunHelloKey
RunBlockSyncKey RunBlockSyncKey
@ -174,7 +174,7 @@ func Online() Option {
Override(new(*chain.MessagePool), chain.NewMessagePool), Override(new(*chain.MessagePool), chain.NewMessagePool),
Override(new(modules.Genesis), testing.MakeGenesis), Override(new(modules.Genesis), testing.MakeGenesis),
Override(SetGenisisKey, modules.SetGenesis), Override(SetGenesisKey, modules.SetGenesis),
Override(new(*hello.Service), hello.NewHelloService), Override(new(*hello.Service), hello.NewHelloService),
Override(new(*chain.BlockSyncService), chain.NewBlockSyncService), Override(new(*chain.BlockSyncService), chain.NewBlockSyncService),