WIP: base mining on power and VRFs
This commit is contained in:
parent
639f07df92
commit
e9d1f3e7c9
@ -66,7 +66,7 @@ type FullNode interface {
|
||||
// miner
|
||||
|
||||
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 ?
|
||||
|
||||
|
@ -54,8 +54,8 @@ type FullNodeStruct struct {
|
||||
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"`
|
||||
|
||||
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"`
|
||||
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"`
|
||||
|
||||
WalletNew func(context.Context, string) (address.Address, 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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ type ChainGen struct {
|
||||
w *wallet.Wallet
|
||||
|
||||
miner address.Address
|
||||
mworker address.Address
|
||||
receivers []address.Address
|
||||
banker address.Address
|
||||
bankerNonce uint64
|
||||
@ -93,7 +94,7 @@ func NewGenerator() (*ChainGen, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
miner, err := w.GenerateKey(types.KTBLS)
|
||||
worker, err := w.GenerateKey(types.KTBLS)
|
||||
if err != nil {
|
||||
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{
|
||||
miner: types.NewInt(5),
|
||||
worker: types.NewInt(50000),
|
||||
banker: types.NewInt(90000000),
|
||||
})
|
||||
}, minercfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -135,7 +141,8 @@ func NewGenerator() (*ChainGen, error) {
|
||||
genesis: genb.Genesis,
|
||||
w: w,
|
||||
|
||||
miner: miner,
|
||||
miner: minercfg.MinerAddr,
|
||||
mworker: worker,
|
||||
banker: banker,
|
||||
receivers: receievers,
|
||||
|
||||
@ -166,8 +173,13 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
|
||||
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
|
||||
func (cg *ChainGen) nextBlockProof() (address.Address, types.ElectionProof, []*types.Ticket, error) {
|
||||
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) {
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
"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())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load tipset state")
|
||||
|
@ -7,11 +7,16 @@ import (
|
||||
actors "github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"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/vm"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
peer "github.com/libp2p/go-libp2p-peer"
|
||||
sharray "github.com/whyrusleeping/sharray"
|
||||
)
|
||||
|
||||
@ -133,8 +138,107 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.BigInt) (*GenesisBootstrap, error) {
|
||||
fmt.Println("at end of make Genesis block")
|
||||
type GenMinerCfg struct {
|
||||
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)
|
||||
if err != nil {
|
||||
@ -146,6 +250,13 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
genesisticket := &types.Ticket{
|
||||
VRFProof: []byte("vrf proof"),
|
||||
VDFResult: []byte("i am a vdf result"),
|
||||
VDFProof: []byte("vdf proof"),
|
||||
}
|
||||
|
||||
b := &types.BlockHeader{
|
||||
Miner: actors.InitActorAddress,
|
||||
Tickets: []types.Ticket{},
|
||||
Tickets: []*types.Ticket{genesisticket},
|
||||
ElectionProof: []byte("the Genesis block"),
|
||||
Parents: []cid.Cid{},
|
||||
Height: 0,
|
||||
|
@ -54,6 +54,10 @@ func BigMul(a, b BigInt) BigInt {
|
||||
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 {
|
||||
return BigInt{big.NewInt(0).Add(a.Int, b.Int)}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@ -15,14 +17,22 @@ func init() {
|
||||
TransformMarshal(atlas.MakeMarshalTransformFunc(
|
||||
func(blk BlockHeader) ([]interface{}, error) {
|
||||
if blk.Tickets == nil {
|
||||
blk.Tickets = []Ticket{}
|
||||
blk.Tickets = []*Ticket{}
|
||||
}
|
||||
if blk.Parents == nil {
|
||||
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{}{
|
||||
blk.Miner.Bytes(),
|
||||
blk.Tickets,
|
||||
tickarrs,
|
||||
blk.ElectionProof,
|
||||
blk.Parents,
|
||||
blk.ParentWeight,
|
||||
@ -39,10 +49,23 @@ func init() {
|
||||
return BlockHeader{}, err
|
||||
}
|
||||
|
||||
tickets := []Ticket{}
|
||||
tickets := []*Ticket{}
|
||||
ticketarr, _ := arr[1].([]interface{})
|
||||
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)
|
||||
|
||||
@ -72,15 +95,21 @@ func init() {
|
||||
})).
|
||||
Complete())
|
||||
cbor.RegisterCborType(MsgMeta{})
|
||||
cbor.RegisterCborType(Ticket{})
|
||||
}
|
||||
|
||||
type Ticket struct {
|
||||
VRFProof []byte
|
||||
VDFResult []byte
|
||||
VDFProof []byte
|
||||
}
|
||||
|
||||
type Ticket []byte
|
||||
type ElectionProof []byte
|
||||
|
||||
type BlockHeader struct {
|
||||
Miner address.Address
|
||||
|
||||
Tickets []Ticket
|
||||
Tickets []*Ticket
|
||||
|
||||
ElectionProof []byte
|
||||
|
||||
|
@ -441,6 +441,10 @@ func Copy(ctx context.Context, from, to ipld.DAGService, root cid.Cid) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vm *VM) StateTree() types.StateTree {
|
||||
return vm.cstate
|
||||
}
|
||||
|
||||
func (vm *VM) TransferFunds(from, to address.Address, amt types.BigInt) error {
|
||||
if from == to {
|
||||
return nil
|
||||
|
1
go.mod
1
go.mod
@ -40,6 +40,7 @@ require (
|
||||
github.com/libp2p/go-libp2p-discovery v0.1.0
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.1.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-pnet v0.1.0
|
||||
github.com/libp2p/go-libp2p-pubsub v0.1.0
|
||||
|
1
go.sum
1
go.sum
@ -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/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.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY=
|
||||
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.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
|
||||
|
179
miner/miner.go
179
miner/miner.go
@ -1,14 +1,20 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/pkg/errors"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
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/types"
|
||||
)
|
||||
@ -16,6 +22,8 @@ import (
|
||||
var log = logging.Logger("miner")
|
||||
|
||||
type api interface {
|
||||
ChainCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
|
||||
|
||||
ChainSubmitBlock(context.Context, *chain.BlockMsg) error
|
||||
|
||||
// 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
|
||||
// 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
|
||||
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 {
|
||||
@ -83,7 +93,7 @@ func (m *Miner) Mine(ctx context.Context) {
|
||||
|
||||
type MiningBase struct {
|
||||
ts *types.TipSet
|
||||
tickets []types.Ticket
|
||||
tickets []*types.Ticket
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
win, proof, err := m.isWinnerNextRound(base)
|
||||
win, proof, err := m.isWinnerNextRound(ctx, base)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (m *Miner) submitNullTicket(base *MiningBase, ticket types.Ticket) {
|
||||
func (m *Miner) submitNullTicket(base *MiningBase, ticket *types.Ticket) {
|
||||
base.tickets = append(base.tickets, ticket)
|
||||
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)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
_ = r // TODO: use this to properly compute the election proof
|
||||
vrfout, err := m.computeVRF(ctx, r)
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
|
||||
return true, []byte("election prooooof"), nil
|
||||
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 (m *Miner) scratchTicket(ctx context.Context, base *MiningBase) (types.Ticket, error) {
|
||||
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 {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
return nil, nil, ctx.Err()
|
||||
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)
|
||||
if err != nil {
|
||||
|
@ -291,7 +291,7 @@ func (a *FullNodeAPI) MinerStart(ctx context.Context, addr address.Address) erro
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -27,7 +27,20 @@ func MakeGenesisMem(out io.Writer) func(bs dtypes.ChainBlockstore, w *wallet.Wal
|
||||
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")
|
||||
// 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 {
|
||||
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() (*types.BlockHeader, error) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gmc := &gen.GenMinerCfg{
|
||||
Owner: minerAddr,
|
||||
Worker: minerAddr,
|
||||
}
|
||||
|
||||
addrs := map[address.Address]types.BigInt{
|
||||
minerAddr: types.NewInt(50000000),
|
||||
}
|
||||
|
||||
b, err := gen.MakeGenesisBlock(bs, addrs)
|
||||
b, err := gen.MakeGenesisBlock(bs, addrs, gmc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user