Skip to content

Commit

Permalink
Refactor mining logic to match specs ticket chain
Browse files Browse the repository at this point in the history
  • Loading branch information
whyrusleeping committed Nov 20, 2019
1 parent d680dab commit f8eabd3
Show file tree
Hide file tree
Showing 26 changed files with 165 additions and 215 deletions.
4 changes: 2 additions & 2 deletions api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type FullNode interface {
// First message is guaranteed to be of len == 1, and type == 'current'
ChainNotify(context.Context) (<-chan []*store.HeadChange, error)
ChainHead(context.Context) (*types.TipSet, error)
ChainGetRandomness(context.Context, types.TipSetKey, []*types.Ticket, int) ([]byte, error)
ChainGetRandomness(context.Context, types.TipSetKey, int64) ([]byte, error)
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
Expand Down Expand Up @@ -52,7 +52,7 @@ type FullNode interface {
MinerRegister(context.Context, address.Address) error
MinerUnregister(context.Context, address.Address) error
MinerAddresses(context.Context) ([]address.Address, error)
MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*types.BlockMsg, error)
MinerCreateBlock(context.Context, address.Address, *types.TipSet, *types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error)

// // UX ?

Expand Down
42 changes: 21 additions & 21 deletions api/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ type FullNodeStruct struct {
CommonStruct

Internal struct {
ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"`
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetRandomness func(context.Context, types.TipSetKey, []*types.Ticket, int) ([]byte, error) `perm:"read"`
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"`
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"`
ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"`
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"`
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainTipSetWeight func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"`
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetRandomness func(context.Context, types.TipSetKey, int64) ([]byte, error) `perm:"read"`
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"`
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainGetParentMessages func(context.Context, cid.Cid) ([]Message, error) `perm:"read"`
ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"`
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"`
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainTipSetWeight func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`

SyncState func(context.Context) (*SyncState, error) `perm:"read"`
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
Expand All @@ -58,10 +58,10 @@ type FullNodeStruct struct {
MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"`
MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"`

MinerRegister func(context.Context, address.Address) error `perm:"admin"`
MinerUnregister func(context.Context, address.Address) error `perm:"admin"`
MinerAddresses func(context.Context) ([]address.Address, error) `perm:"write"`
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64) (*types.BlockMsg, error) `perm:"write"`
MinerRegister func(context.Context, address.Address) error `perm:"admin"`
MinerUnregister func(context.Context, address.Address) error `perm:"admin"`
MinerAddresses func(context.Context) ([]address.Address, error) `perm:"write"`
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, *types.Ticket, types.ElectionProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error) `perm:"write"`

WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
Expand Down Expand Up @@ -237,16 +237,16 @@ func (c *FullNodeStruct) MinerAddresses(ctx context.Context) ([]address.Address,
return c.Internal.MinerAddresses(ctx)
}

func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*types.BlockMsg, error) {
return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs, ts)
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, ticket *types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage, height, ts uint64) (*types.BlockMsg, error) {
return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, msgs, height, ts)
}

func (c *FullNodeStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
return c.Internal.ChainHead(ctx)
}

func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, pts types.TipSetKey, ticks []*types.Ticket, lb int) ([]byte, error) {
return c.Internal.ChainGetRandomness(ctx, pts, ticks, lb)
func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, pts types.TipSetKey, round int64) ([]byte, error) {
return c.Internal.ChainGetRandomness(ctx, pts, round)
}

func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) {
Expand Down
2 changes: 1 addition & 1 deletion chain/blocksync/cbor_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"io"

"github.com/filecoin-project/lotus/chain/types"
cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
)
Expand Down
4 changes: 2 additions & 2 deletions chain/events/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func makeTs(t *testing.T, h uint64, msgcid cid.Cid) *types.TipSet {
Height: h,
Miner: a,

Tickets: []*types.Ticket{{[]byte{byte(h % 2)}}},
Ticket: &types.Ticket{[]byte{byte(h % 2)}},

ParentStateRoot: dummyCid,
Messages: msgcid,
Expand All @@ -65,7 +65,7 @@ func makeTs(t *testing.T, h uint64, msgcid cid.Cid) *types.TipSet {
Height: h,
Miner: b,

Tickets: []*types.Ticket{{[]byte{byte((h + 1) % 2)}}},
Ticket: &types.Ticket{[]byte{byte((h + 1) % 2)}},

ParentStateRoot: dummyCid,
Messages: msgcid,
Expand Down
55 changes: 30 additions & 25 deletions chain/gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package gen
import (
"bytes"
"context"
"crypto/sha256"
"encoding/binary"
"fmt"
"sync/atomic"

Expand Down Expand Up @@ -46,7 +48,7 @@ type ChainGen struct {
genesis *types.BlockHeader
CurTipset *store.FullTipSet

Timestamper func(*types.TipSet, int) uint64
Timestamper func(*types.TipSet, uint64) uint64

w *wallet.Wallet

Expand Down Expand Up @@ -195,14 +197,9 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
return out.Bytes(), nil
}

func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, ticks []*types.Ticket) (types.ElectionProof, *types.Ticket, error) {
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round int64) (types.ElectionProof, *types.Ticket, error) {

var lastTicket *types.Ticket
if len(ticks) == 0 {
lastTicket = pts.MinTicket()
} else {
lastTicket = ticks[len(ticks)-1]
}
lastTicket := pts.MinTicket()

st := pts.ParentState()

Expand All @@ -211,7 +208,8 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
return nil, nil, xerrors.Errorf("get miner worker: %w", err)
}

vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, lastTicket.VRFProof)
vrfBase := TicketHash(lastTicket, uint64(round))
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, vrfBase)
if err != nil {
return nil, nil, xerrors.Errorf("compute VRF: %w", err)
}
Expand All @@ -220,7 +218,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
VRFProof: vrfout,
}

win, eproof, err := IsRoundWinner(ctx, pts, append(ticks, tick), m, &mca{w: cg.w, sm: cg.sm})
win, eproof, err := IsRoundWinner(ctx, pts, round, m, &mca{w: cg.w, sm: cg.sm})
if err != nil {
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
}
Expand Down Expand Up @@ -248,23 +246,21 @@ func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {

func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) {
var blks []*types.FullBlock
ticketSets := make([][]*types.Ticket, len(miners))

msgs, err := cg.getRandomMessages()
if err != nil {
return nil, xerrors.Errorf("get random messages: %w", err)
}

for len(blks) == 0 {
for i, m := range miners {
proof, t, err := cg.nextBlockProof(context.TODO(), base, m, ticketSets[i])
for round := int64(base.Height() + 1); len(blks) == 0; round++ {
for _, m := range miners {
proof, t, err := cg.nextBlockProof(context.TODO(), base, m, round)
if err != nil {
return nil, xerrors.Errorf("next block proof: %w", err)
}

ticketSets[i] = append(ticketSets[i], t)
if proof != nil {
fblk, err := cg.makeBlock(base, m, proof, ticketSets[i], msgs)
fblk, err := cg.makeBlock(base, m, proof, t, uint64(round), msgs)
if err != nil {
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
}
Expand All @@ -286,16 +282,16 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
}, nil
}

func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof types.ElectionProof, tickets []*types.Ticket, msgs []*types.SignedMessage) (*types.FullBlock, error) {
func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof types.ElectionProof, ticket *types.Ticket, height uint64, msgs []*types.SignedMessage) (*types.FullBlock, error) {

var ts uint64
if cg.Timestamper != nil {
ts = cg.Timestamper(parents, len(tickets))
ts = cg.Timestamper(parents, height-parents.Height())
} else {
ts = parents.MinTimestamp() + (uint64(len(tickets)) * build.BlockDelay)
ts = parents.MinTimestamp() + ((height - parents.Height()) * build.BlockDelay)
}

fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, tickets, eproof, msgs, ts)
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, ticket, eproof, msgs, height, ts)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -354,7 +350,7 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
}

type MiningCheckAPI interface {
ChainGetRandomness(context.Context, types.TipSetKey, []*types.Ticket, int) ([]byte, error)
ChainGetRandomness(context.Context, types.TipSetKey, int64) ([]byte, error)

StateMinerPower(context.Context, address.Address, *types.TipSet) (api.MinerPower, error)

Expand All @@ -368,8 +364,8 @@ type mca struct {
sm *stmgr.StateManager
}

func (mca mca) ChainGetRandomness(ctx context.Context, pts types.TipSetKey, ticks []*types.Ticket, lb int) ([]byte, error) {
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), ticks, int64(lb))
func (mca mca) ChainGetRandomness(ctx context.Context, pts types.TipSetKey, lb int64) ([]byte, error) {
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), int64(lb))
}

func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) {
Expand All @@ -392,8 +388,8 @@ func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*ty
return mca.w.Sign(ctx, a, v)
}

func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket, miner address.Address, a MiningCheckAPI) (bool, types.ElectionProof, error) {
r, err := a.ChainGetRandomness(ctx, ts.Key(), ticks, build.EcRandomnessLookback)
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, a MiningCheckAPI) (bool, types.ElectionProof, error) {
r, err := a.ChainGetRandomness(ctx, ts.Key(), round-build.EcRandomnessLookback)
if err != nil {
return false, nil, xerrors.Errorf("chain get randomness: %w", err)
}
Expand Down Expand Up @@ -430,3 +426,12 @@ func ComputeVRF(ctx context.Context, sign SignFunc, w address.Address, input []b

return sig.Data, nil
}

func TicketHash(t *types.Ticket, round uint64) []byte {
h := sha256.New()
h.Write(t.VRFProof)
var roundbuf [8]byte
binary.LittleEndian.PutUint64(roundbuf[:], round)
h.Write(roundbuf[:])
return h.Sum(nil)
}
8 changes: 1 addition & 7 deletions chain/gen/gen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,12 @@ func testGeneration(t testing.TB, n int, msgs int) {

g.msgsPerBlock = msgs

var height int
for i := 0; i < n; i++ {
mts, err := g.NextTipSet()
if err != nil {
t.Fatalf("error at H:%d, %s", i, err)
}

ts := mts.TipSet.TipSet()
if ts.Height() != uint64(height+len(ts.Blocks()[0].Tickets)) {
t.Fatal("wrong height", ts.Height(), i, len(ts.Blocks()[0].Tickets), len(ts.Blocks()))
}
height += len(ts.Blocks()[0].Tickets)
_ = mts
}
}

Expand Down
6 changes: 2 additions & 4 deletions chain/gen/mining.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ 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, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, 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.ElectionProof, msgs []*types.SignedMessage, height, 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)
}

height := parents.Height() + uint64(len(tickets))

worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, st, miner)
if err != nil {
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
Expand All @@ -34,7 +32,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
next := &types.BlockHeader{
Miner: miner,
Parents: parents.Cids(),
Tickets: tickets,
Ticket: ticket,
Height: height,
Timestamp: timestamp,
ElectionProof: proof,
Expand Down
2 changes: 1 addition & 1 deletion chain/gen/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B

b := &types.BlockHeader{
Miner: actors.InitAddress,
Tickets: []*types.Ticket{genesisticket},
Ticket: genesisticket,
ElectionProof: []byte("the Genesis block"),
Parents: []cid.Cid{},
Height: 0,
Expand Down
2 changes: 1 addition & 1 deletion chain/stmgr/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.

state := ts.ParentState()

r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height(), nil)
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())

return sm.CallRaw(ctx, msg, state, r, ts.Height())
}
Expand Down
2 changes: 1 addition & 1 deletion chain/stmgr/stmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
cids[i] = v.Cid()
}

r := store.NewChainRand(sm.cs, cids, blks[0].Height, nil)
r := store.NewChainRand(sm.cs, cids, blks[0].Height)

vmi, err := vm.NewVM(pstate, blks[0].Height, r, address.Undef, sm.cs.Blockstore())
if err != nil {
Expand Down
Loading

0 comments on commit f8eabd3

Please sign in to comment.