WIP: base mining on power and VRFs

This commit is contained in:
whyrusleeping 2019-08-14 19:30:21 -07:00
parent 639f07df92
commit e9d1f3e7c9
13 changed files with 378 additions and 35 deletions

View File

@ -66,7 +66,7 @@ type FullNode interface {
// miner // miner
MinerStart(context.Context, address.Address) error MinerStart(context.Context, address.Address) error
MinerCreateBlock(context.Context, address.Address, *types.TipSet, []types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error)
// // UX ? // // UX ?

View File

@ -55,7 +55,7 @@ type FullNodeStruct struct {
MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"` MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"`
MinerStart func(context.Context, address.Address) error `perm:"admin"` MinerStart func(context.Context, address.Address) error `perm:"admin"`
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) `perm:"write"` MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) `perm:"write"`
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"` WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"` WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
@ -163,7 +163,7 @@ func (c *FullNodeStruct) MinerStart(ctx context.Context, addr address.Address) e
return c.Internal.MinerStart(ctx, addr) return c.Internal.MinerStart(ctx, addr)
} }
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) { func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) {
return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs) return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs)
} }

View File

@ -41,6 +41,7 @@ type ChainGen struct {
w *wallet.Wallet w *wallet.Wallet
miner address.Address miner address.Address
mworker address.Address
receivers []address.Address receivers []address.Address
banker address.Address banker address.Address
bankerNonce uint64 bankerNonce uint64
@ -93,7 +94,7 @@ func NewGenerator() (*ChainGen, error) {
return nil, err return nil, err
} }
miner, err := w.GenerateKey(types.KTBLS) worker, err := w.GenerateKey(types.KTBLS)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -112,10 +113,15 @@ func NewGenerator() (*ChainGen, error) {
} }
} }
minercfg := &GenMinerCfg{
Worker: worker,
Owner: worker,
}
genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{ genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{
miner: types.NewInt(5), worker: types.NewInt(50000),
banker: types.NewInt(90000000), banker: types.NewInt(90000000),
}) }, minercfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -135,7 +141,8 @@ func NewGenerator() (*ChainGen, error) {
genesis: genb.Genesis, genesis: genb.Genesis,
w: w, w: w,
miner: miner, miner: minercfg.MinerAddr,
mworker: worker,
banker: banker, banker: banker,
receivers: receievers, receivers: receievers,
@ -166,8 +173,13 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
return out.Bytes(), nil return out.Bytes(), nil
} }
func (cg *ChainGen) nextBlockProof() (address.Address, types.ElectionProof, []types.Ticket, error) { func (cg *ChainGen) nextBlockProof() (address.Address, types.ElectionProof, []*types.Ticket, error) {
return cg.miner, []byte("cat in a box"), []types.Ticket{types.Ticket("im a ticket, promise")}, nil tick := &types.Ticket{
VRFProof: []byte("im a ticket, promise"),
VDFProof: []byte("vdf proof"),
VDFResult: []byte("verifiable and delayed"),
}
return cg.miner, []byte("cat in a box"), []*types.Ticket{tick}, nil
} }
func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error) { func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error) {

View File

@ -16,7 +16,7 @@ import (
"github.com/filecoin-project/go-lotus/chain/vm" "github.com/filecoin-project/go-lotus/chain/vm"
) )
func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, miner address.Address, parents *types.TipSet, tickets []types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage) (*types.FullBlock, error) { func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, miner address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage) (*types.FullBlock, error) {
st, err := cs.TipSetState(parents.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")

View File

@ -7,11 +7,16 @@ import (
actors "github.com/filecoin-project/go-lotus/chain/actors" actors "github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state" "github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
"golang.org/x/xerrors"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
hamt "github.com/ipfs/go-hamt-ipld" hamt "github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
peer "github.com/libp2p/go-libp2p-peer"
sharray "github.com/whyrusleeping/sharray" sharray "github.com/whyrusleeping/sharray"
) )
@ -133,8 +138,107 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
}, nil }, nil
} }
func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.BigInt) (*GenesisBootstrap, error) { type GenMinerCfg struct {
fmt.Println("at end of make Genesis block") Owner address.Address
Worker address.Address
// not quite generating real sectors yet, but this will be necessary
//SectorDir string
// The address of the created miner, this is set by the genesis setup
MinerAddr address.Address
PeerID peer.ID
}
func mustEnc(i interface{}) []byte {
enc, err := actors.SerializeParams(i)
if err != nil {
panic(err)
}
return enc
}
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, error) {
vm, err := vm.NewVM(sroot, 0, actors.NetworkAddress, cs)
if err != nil {
return cid.Undef, err
}
params := mustEnc(actors.CreateStorageMinerParams{
Owner: gmcfg.Owner,
Worker: gmcfg.Worker,
SectorSize: types.NewInt(1024),
PeerID: gmcfg.PeerID,
})
rval, err := doExec(ctx, vm, actors.StorageMarketAddress, gmcfg.Owner, actors.SMAMethods.CreateStorageMiner, params)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
}
maddr, err := address.NewFromBytes(rval)
if err != nil {
return cid.Undef, err
}
gmcfg.MinerAddr = maddr
params = mustEnc(actors.UpdateStorageParams{Delta: types.NewInt(5000)})
_, err = doExec(ctx, vm, actors.StorageMarketAddress, maddr, actors.SMAMethods.UpdateStorage, params)
// UGLY HACKY MODIFICATION OF MINER POWER
st := vm.StateTree()
mact, err := st.GetActor(maddr)
if err != nil {
return cid.Undef, err
}
cst := hamt.CSTFromBstore(cs.Blockstore())
var mstate actors.StorageMinerActorState
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
return cid.Undef, err
}
mstate.Power = types.NewInt(5000)
nstate, err := cst.Put(ctx, mstate)
if err != nil {
return cid.Undef, err
}
mact.Head = nstate
if err := st.SetActor(maddr, mact); err != nil {
return cid.Undef, err
}
// End of super haxx
return vm.Flush(ctx)
}
func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uint64, params []byte) ([]byte, error) {
ret, err := vm.ApplyMessage(context.TODO(), &types.Message{
To: to,
From: from,
Method: method,
Params: params,
GasLimit: types.NewInt(1000000),
GasPrice: types.NewInt(0),
Value: types.NewInt(0),
})
if err != nil {
return nil, err
}
if ret.ExitCode != 0 {
return nil, fmt.Errorf("failed to call method: %s", ret.ActorErr)
}
return ret.Return, nil
}
func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.BigInt, gmcfg *GenMinerCfg) (*GenesisBootstrap, error) {
ctx := context.Background()
state, err := MakeInitialStateTree(bs, balances) state, err := MakeInitialStateTree(bs, balances)
if err != nil { if err != nil {
@ -146,6 +250,13 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
return nil, err return nil, err
} }
// temp chainstore
cs := store.NewChainStore(bs, datastore.NewMapDatastore())
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, gmcfg)
if err != nil {
return nil, err
}
cst := hamt.CSTFromBstore(bs) cst := hamt.CSTFromBstore(bs)
emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst) emptyroot, err := sharray.Build(context.TODO(), 4, []interface{}{}, cst)
@ -162,9 +273,15 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
fmt.Println("Empty Genesis root: ", emptyroot) fmt.Println("Empty Genesis root: ", emptyroot)
genesisticket := &types.Ticket{
VRFProof: []byte("vrf proof"),
VDFResult: []byte("i am a vdf result"),
VDFProof: []byte("vdf proof"),
}
b := &types.BlockHeader{ b := &types.BlockHeader{
Miner: actors.InitActorAddress, Miner: actors.InitActorAddress,
Tickets: []types.Ticket{}, Tickets: []*types.Ticket{genesisticket},
ElectionProof: []byte("the Genesis block"), ElectionProof: []byte("the Genesis block"),
Parents: []cid.Cid{}, Parents: []cid.Cid{},
Height: 0, Height: 0,

View File

@ -54,6 +54,10 @@ func BigMul(a, b BigInt) BigInt {
return BigInt{big.NewInt(0).Mul(a.Int, b.Int)} return BigInt{big.NewInt(0).Mul(a.Int, b.Int)}
} }
func BigDiv(a, b BigInt) BigInt {
return BigInt{big.NewInt(0).Div(a.Int, b.Int)}
}
func BigAdd(a, b BigInt) BigInt { func BigAdd(a, b BigInt) BigInt {
return BigInt{big.NewInt(0).Add(a.Int, b.Int)} return BigInt{big.NewInt(0).Add(a.Int, b.Int)}
} }

View File

@ -1,6 +1,8 @@
package types package types
import ( import (
"fmt"
block "github.com/ipfs/go-block-format" block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
@ -15,14 +17,22 @@ func init() {
TransformMarshal(atlas.MakeMarshalTransformFunc( TransformMarshal(atlas.MakeMarshalTransformFunc(
func(blk BlockHeader) ([]interface{}, error) { func(blk BlockHeader) ([]interface{}, error) {
if blk.Tickets == nil { if blk.Tickets == nil {
blk.Tickets = []Ticket{} blk.Tickets = []*Ticket{}
} }
if blk.Parents == nil { if blk.Parents == nil {
blk.Parents = []cid.Cid{} blk.Parents = []cid.Cid{}
} }
var tickarrs [][][]byte // oh boy
for _, t := range blk.Tickets {
tickarrs = append(tickarrs, [][]byte{
t.VRFProof, t.VDFResult, t.VDFProof,
})
}
return []interface{}{ return []interface{}{
blk.Miner.Bytes(), blk.Miner.Bytes(),
blk.Tickets, tickarrs,
blk.ElectionProof, blk.ElectionProof,
blk.Parents, blk.Parents,
blk.ParentWeight, blk.ParentWeight,
@ -39,10 +49,23 @@ func init() {
return BlockHeader{}, err return BlockHeader{}, err
} }
tickets := []Ticket{} tickets := []*Ticket{}
ticketarr, _ := arr[1].([]interface{}) ticketarr, _ := arr[1].([]interface{})
for _, t := range ticketarr { for _, t := range ticketarr {
tickets = append(tickets, Ticket(t.([]byte))) ticklist, ok := t.([]interface{})
if !ok {
return BlockHeader{}, fmt.Errorf("tickets were incorrectly formatted (type = %T)", t)
}
if len(ticklist) != 3 {
return BlockHeader{}, fmt.Errorf("ticket should be a three item array of Byte arrays (got len = %d)", len(ticklist))
}
tickets = append(tickets, &Ticket{
VRFProof: ticklist[0].([]byte),
VDFResult: ticklist[1].([]byte),
VDFProof: ticklist[2].([]byte),
})
} }
electionProof, _ := arr[2].([]byte) electionProof, _ := arr[2].([]byte)
@ -72,15 +95,21 @@ func init() {
})). })).
Complete()) Complete())
cbor.RegisterCborType(MsgMeta{}) cbor.RegisterCborType(MsgMeta{})
cbor.RegisterCborType(Ticket{})
}
type Ticket struct {
VRFProof []byte
VDFResult []byte
VDFProof []byte
} }
type Ticket []byte
type ElectionProof []byte type ElectionProof []byte
type BlockHeader struct { type BlockHeader struct {
Miner address.Address Miner address.Address
Tickets []Ticket Tickets []*Ticket
ElectionProof []byte ElectionProof []byte

View File

@ -441,6 +441,10 @@ func Copy(ctx context.Context, from, to ipld.DAGService, root cid.Cid) error {
return nil return nil
} }
func (vm *VM) StateTree() types.StateTree {
return vm.cstate
}
func (vm *VM) TransferFunds(from, to address.Address, amt types.BigInt) error { func (vm *VM) TransferFunds(from, to address.Address, amt types.BigInt) error {
if from == to { if from == to {
return nil return nil

1
go.mod
View File

@ -40,6 +40,7 @@ require (
github.com/libp2p/go-libp2p-discovery v0.1.0 github.com/libp2p/go-libp2p-discovery v0.1.0
github.com/libp2p/go-libp2p-kad-dht v0.1.1 github.com/libp2p/go-libp2p-kad-dht v0.1.1
github.com/libp2p/go-libp2p-mplex v0.2.1 github.com/libp2p/go-libp2p-mplex v0.2.1
github.com/libp2p/go-libp2p-peer v0.2.0
github.com/libp2p/go-libp2p-peerstore v0.1.2-0.20190621130618-cfa9bb890c1a github.com/libp2p/go-libp2p-peerstore v0.1.2-0.20190621130618-cfa9bb890c1a
github.com/libp2p/go-libp2p-pnet v0.1.0 github.com/libp2p/go-libp2p-pnet v0.1.0
github.com/libp2p/go-libp2p-pubsub v0.1.0 github.com/libp2p/go-libp2p-pubsub v0.1.0

1
go.sum
View File

@ -305,6 +305,7 @@ github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFx
github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo=
github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY=
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=
github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=

View File

@ -1,14 +1,20 @@
package miner package miner
import ( import (
"bytes"
"context" "context"
"crypto/sha256"
"fmt"
"math/big"
"time" "time"
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opencensus.io/trace" "go.opencensus.io/trace"
"golang.org/x/xerrors"
chain "github.com/filecoin-project/go-lotus/chain" chain "github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/chain/types"
) )
@ -16,6 +22,8 @@ import (
var log = logging.Logger("miner") var log = logging.Logger("miner")
type api interface { type api interface {
ChainCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
ChainSubmitBlock(context.Context, *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
@ -35,7 +43,9 @@ type api interface {
// 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
MinerCreateBlock(context.Context, address.Address, *types.TipSet, []types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error)
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
} }
func NewMiner(api api, addr address.Address) *Miner { func NewMiner(api api, addr address.Address) *Miner {
@ -83,7 +93,7 @@ func (m *Miner) Mine(ctx context.Context) {
type MiningBase struct { type MiningBase struct {
ts *types.TipSet ts *types.TipSet
tickets []types.Ticket tickets []*types.Ticket
} }
func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) { func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) {
@ -114,7 +124,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg,
return nil, errors.Wrap(err, "scratching ticket failed") return nil, errors.Wrap(err, "scratching ticket failed")
} }
win, proof, err := m.isWinnerNextRound(base) win, proof, err := m.isWinnerNextRound(ctx, base)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to check if we win next round") return nil, errors.Wrap(err, "failed to check if we win next round")
} }
@ -133,33 +143,180 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg,
return b, nil return b, nil
} }
func (m *Miner) submitNullTicket(base *MiningBase, ticket types.Ticket) { func (m *Miner) submitNullTicket(base *MiningBase, ticket *types.Ticket) {
base.tickets = append(base.tickets, ticket) base.tickets = append(base.tickets, ticket)
m.lastWork = base m.lastWork = base
} }
func (m *Miner) isWinnerNextRound(base *MiningBase) (bool, types.ElectionProof, error) { func (m *Miner) computeVRF(ctx context.Context, input []byte) ([]byte, error) {
w, err := m.getMinerWorker(ctx, m.address, nil)
if err != nil {
return nil, err
}
sig, err := m.api.WalletSign(ctx, w, input)
if err != nil {
return nil, err
}
if sig.Type != types.KTBLS {
return nil, fmt.Errorf("miner worker address was not a BLS key")
}
return sig.Data, nil
}
func (m *Miner) getMinerWorker(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
ret, err := m.api.ChainCall(ctx, &types.Message{
From: addr,
To: addr,
Method: actors.MAMethods.GetWorkerAddr,
}, ts)
if err != nil {
return address.Undef, xerrors.Errorf("failed to get miner worker addr: %w", err)
}
if ret.ExitCode != 0 {
return address.Undef, xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.ExitCode)
}
w, err := address.NewFromBytes(ret.Return)
if err != nil {
return address.Undef, xerrors.Errorf("GetWorkerAddr returned malformed address: %w", err)
}
return w, nil
}
func (m *Miner) isWinnerNextRound(ctx context.Context, base *MiningBase) (bool, types.ElectionProof, error) {
r, err := m.api.ChainGetRandomness(context.TODO(), 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
} }
_ = r // TODO: use this to properly compute the election proof vrfout, err := m.computeVRF(ctx, r)
if err != nil {
return true, []byte("election prooooof"), nil return false, nil, xerrors.Errorf("failed to compute VRF: %w", err)
} }
func (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (types.Ticket, error) { mpow, totpow, err := m.getPowerForTipset(ctx, m.address, base.ts)
if err != nil {
return false, nil, xerrors.Errorf("failed to check power: %w", err)
}
return powerCmp(vrfout, mpow, totpow), vrfout, nil
}
func powerCmp(vrfout []byte, mpow, totpow types.BigInt) bool {
/*
Need to check that
h(vrfout) / 2^256 < minerPower / totalPower
*/
h := sha256.Sum256(vrfout)
// 2^256
rden := types.BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)}
top := types.BigMul(rden, mpow)
out := types.BigDiv(top, totpow)
return types.BigCmp(types.BigFromBytes(h[:]), out) < 0
}
func (m *Miner) getPowerForTipset(ctx context.Context, maddr address.Address, ts *types.TipSet) (types.BigInt, types.BigInt, error) {
var err error
enc, err := actors.SerializeParams(&actors.PowerLookupParams{maddr})
if err != nil {
return types.EmptyInt, types.EmptyInt, err
}
ret, err := m.api.ChainCall(ctx, &types.Message{
From: maddr,
To: actors.StorageMarketAddress,
Method: actors.SMAMethods.PowerLookup,
Params: enc,
}, ts)
if err != nil {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get miner power from chain: %w", err)
}
if ret.ExitCode != 0 {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get miner power from chain (exit code %d)", ret.ExitCode)
}
mpow := types.BigFromBytes(ret.Return)
ret, err = m.api.ChainCall(ctx, &types.Message{
From: maddr,
To: actors.StorageMarketAddress,
Method: actors.SMAMethods.GetTotalStorage,
}, ts)
if err != nil {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get total power from chain: %w", err)
}
if ret.ExitCode != 0 {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get total power from chain (exit code %d)", ret.ExitCode)
}
tpow := types.BigFromBytes(ret.Return)
return mpow, tpow, nil
}
func (m *Miner) runVDF(ctx context.Context, input []byte) ([]byte, []byte, error) {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, ctx.Err() return nil, nil, ctx.Err()
case <-time.After(m.Delay): case <-time.After(m.Delay):
} }
return []byte("this is a ticket"), nil h := sha256.Sum256(input)
// TODO: THIS IS A FAKE VDF. THE SPEC IS UNCLEAR ON WHAT TO REALLY DO HERE
return h[:], []byte("proof"), nil
} }
func (m *Miner) createBlock(base *MiningBase, ticket types.Ticket, proof types.ElectionProof) (*chain.BlockMsg, error) { func minTicket(ts *types.TipSet) *types.Ticket {
if len(ts.Blocks()) == 0 {
panic("tipset has no blocks!")
}
var minTicket *types.Ticket
for _, b := range ts.Blocks() {
lastTicket := b.Tickets[len(b.Tickets)-1]
if minTicket == nil || bytes.Compare(lastTicket.VDFResult, minTicket.VDFResult) < 0 {
minTicket = lastTicket
}
}
return minTicket
}
func (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (*types.Ticket, error) {
var lastTicket *types.Ticket
if len(base.tickets) > 0 {
lastTicket = base.tickets[len(base.tickets)-1]
} else {
lastTicket = minTicket(base.ts)
}
vrfOut, err := m.computeVRF(ctx, lastTicket.VDFResult)
if err != nil {
return nil, err
}
res, proof, err := m.runVDF(ctx, vrfOut)
if err != nil {
return nil, err
}
return &types.Ticket{
VRFProof: vrfOut,
VDFResult: res,
VDFProof: proof,
}, nil
}
func (m *Miner) createBlock(base *MiningBase, ticket *types.Ticket, proof types.ElectionProof) (*chain.BlockMsg, error) {
pending, err := m.api.MpoolPending(context.TODO(), base.ts) pending, err := m.api.MpoolPending(context.TODO(), base.ts)
if err != nil { if err != nil {

View File

@ -291,7 +291,7 @@ func (a *FullNodeAPI) MinerStart(ctx context.Context, addr address.Address) erro
return nil return nil
} }
func (a *FullNodeAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) { func (a *FullNodeAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) {
fblk, err := gen.MinerCreateBlock(ctx, a.Chain, addr, parents, tickets, proof, msgs) fblk, err := gen.MinerCreateBlock(ctx, a.Chain, addr, parents, tickets, proof, msgs)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -27,7 +27,20 @@ func MakeGenesisMem(out io.Writer) func(bs dtypes.ChainBlockstore, w *wallet.Wal
return func() (*types.BlockHeader, error) { return func() (*types.BlockHeader, error) {
glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network")
// TODO: make an address allocation // TODO: make an address allocation
b, err := gen.MakeGenesisBlock(bs, nil) w, err := w.GenerateKey(types.KTBLS)
if err != nil {
return nil, err
}
gmc := &gen.GenMinerCfg{
Owner: w,
Worker: w,
}
alloc := map[address.Address]types.BigInt{
w: types.NewInt(100000),
}
b, err := gen.MakeGenesisBlock(bs, alloc, gmc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -48,16 +61,21 @@ func MakeGenesis(outFile string) func(bs dtypes.ChainBlockstore, w *wallet.Walle
return func(bs dtypes.ChainBlockstore, w *wallet.Wallet) modules.Genesis { return func(bs dtypes.ChainBlockstore, w *wallet.Wallet) modules.Genesis {
return func() (*types.BlockHeader, error) { return func() (*types.BlockHeader, error) {
glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network")
minerAddr, err := w.GenerateKey(types.KTSecp256k1) minerAddr, err := w.GenerateKey(types.KTBLS)
if err != nil { if err != nil {
return nil, err return nil, err
} }
gmc := &gen.GenMinerCfg{
Owner: minerAddr,
Worker: minerAddr,
}
addrs := map[address.Address]types.BigInt{ addrs := map[address.Address]types.BigInt{
minerAddr: types.NewInt(50000000), minerAddr: types.NewInt(50000000),
} }
b, err := gen.MakeGenesisBlock(bs, addrs) b, err := gen.MakeGenesisBlock(bs, addrs, gmc)
if err != nil { if err != nil {
return nil, err return nil, err
} }