Merge pull request #139 from filecoin-project/feat/realer-mining
base mining on power and VRFs
This commit is contained in:
commit
aed7b8b640
@ -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 ?
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ type FullNodeStruct struct {
|
|||||||
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
|
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package actors
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||||
"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"
|
||||||
@ -22,6 +23,7 @@ func init() {
|
|||||||
cbor.RegisterCborType(PieceInclVoucherData{})
|
cbor.RegisterCborType(PieceInclVoucherData{})
|
||||||
cbor.RegisterCborType(InclusionProof{})
|
cbor.RegisterCborType(InclusionProof{})
|
||||||
cbor.RegisterCborType(PaymentVerifyParams{})
|
cbor.RegisterCborType(PaymentVerifyParams{})
|
||||||
|
cbor.RegisterCborType(UpdatePeerIDParams{})
|
||||||
}
|
}
|
||||||
|
|
||||||
var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now
|
var ProvingPeriodDuration = uint64(2 * 60) // an hour, for now
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package actors_test
|
package actors_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||||
@ -30,7 +31,7 @@ func signVoucher(t *testing.T, w *wallet.Wallet, addr address.Address, sv *types
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := w.Sign(addr, vb)
|
sig, err := w.Sign(context.TODO(), addr, vb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ func init() {
|
|||||||
cbor.RegisterCborType(CreateStorageMinerParams{})
|
cbor.RegisterCborType(CreateStorageMinerParams{})
|
||||||
cbor.RegisterCborType(IsMinerParam{})
|
cbor.RegisterCborType(IsMinerParam{})
|
||||||
cbor.RegisterCborType(PowerLookupParams{})
|
cbor.RegisterCborType(PowerLookupParams{})
|
||||||
|
cbor.RegisterCborType(UpdateStorageParams{})
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageMarketActor struct{}
|
type StorageMarketActor struct{}
|
||||||
@ -115,7 +116,8 @@ type UpdateStorageParams struct {
|
|||||||
|
|
||||||
func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMContext, params *UpdateStorageParams) ([]byte, ActorError) {
|
func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMContext, params *UpdateStorageParams) ([]byte, ActorError) {
|
||||||
var self StorageMarketState
|
var self StorageMarketState
|
||||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +127,16 @@ func (sma StorageMarketActor) UpdateStorage(act *types.Actor, vmctx types.VMCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.TotalStorage = types.BigAdd(self.TotalStorage, params.Delta)
|
self.TotalStorage = types.BigAdd(self.TotalStorage, params.Delta)
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@ package deals
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||||
|
|
||||||
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
@ -139,7 +140,7 @@ func (c *Client) sendProposal(s inet.Stream, proposal StorageDealProposal, from
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sig, err := c.w.Sign(from, msg)
|
sig, err := c.w.Sign(context.TODO(), from, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,13 @@ import (
|
|||||||
"github.com/ipfs/go-car"
|
"github.com/ipfs/go-car"
|
||||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||||
"github.com/ipfs/go-merkledag"
|
"github.com/ipfs/go-merkledag"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"github.com/filecoin-project/go-lotus/chain/store"
|
"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/wallet"
|
"github.com/filecoin-project/go-lotus/chain/wallet"
|
||||||
|
"github.com/filecoin-project/go-lotus/lib/vdf"
|
||||||
"github.com/filecoin-project/go-lotus/node/repo"
|
"github.com/filecoin-project/go-lotus/node/repo"
|
||||||
|
|
||||||
block "github.com/ipfs/go-block-format"
|
block "github.com/ipfs/go-block-format"
|
||||||
@ -41,6 +43,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
|
||||||
@ -68,56 +71,60 @@ func NewGenerator() (*ChainGen, error) {
|
|||||||
mr := repo.NewMemory(nil)
|
mr := repo.NewMemory(nil)
|
||||||
lr, err := mr.Lock()
|
lr, err := mr.Lock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("taking mem-repo lock failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ds, err := lr.Datastore("/metadata")
|
ds, err := lr.Datastore("/metadata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to get metadata datastore: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bds, err := lr.Datastore("/blocks")
|
bds, err := lr.Datastore("/blocks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to get blocks datastore: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bs := mybs{blockstore.NewIdStore(blockstore.NewBlockstore(bds))}
|
bs := mybs{blockstore.NewIdStore(blockstore.NewBlockstore(bds))}
|
||||||
|
|
||||||
ks, err := lr.KeyStore()
|
ks, err := lr.KeyStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("getting repo keystore failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w, err := wallet.NewWallet(ks)
|
w, err := wallet.NewWallet(ks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
miner, err := w.GenerateKey(types.KTBLS)
|
worker, err := w.GenerateKey(types.KTBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to generate worker key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KTBLS doesn't support signature verification or something like that yet
|
|
||||||
banker, err := w.GenerateKey(types.KTSecp256k1)
|
banker, err := w.GenerateKey(types.KTSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
receievers := make([]address.Address, msgsPerBlock)
|
receievers := make([]address.Address, msgsPerBlock)
|
||||||
for r := range receievers {
|
for r := range receievers {
|
||||||
receievers[r], err = w.GenerateKey(types.KTBLS)
|
receievers[r], err = w.GenerateKey(types.KTBLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, xerrors.Errorf("make genesis block failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := store.NewChainStore(bs, ds)
|
cs := store.NewChainStore(bs, ds)
|
||||||
@ -125,7 +132,11 @@ func NewGenerator() (*ChainGen, error) {
|
|||||||
genfb := &types.FullBlock{Header: genb.Genesis}
|
genfb := &types.FullBlock{Header: genb.Genesis}
|
||||||
|
|
||||||
if err := cs.SetGenesis(genb.Genesis); err != nil {
|
if err := cs.SetGenesis(genb.Genesis); err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("set genesis failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if minercfg.MinerAddr == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("MakeGenesisBlock failed to set miner address")
|
||||||
}
|
}
|
||||||
|
|
||||||
gen := &ChainGen{
|
gen := &ChainGen{
|
||||||
@ -135,7 +146,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,12 +178,32 @@ 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(ctx context.Context) (address.Address, types.ElectionProof, []*types.Ticket, error) {
|
||||||
return cg.miner, []byte("cat in a box"), []types.Ticket{types.Ticket("im a ticket, promise")}, nil
|
|
||||||
|
ticks := cg.curBlock.Header.Tickets
|
||||||
|
lastTicket := ticks[len(ticks)-1]
|
||||||
|
|
||||||
|
vrfout, err := ComputeVRF(ctx, cg.w.Sign, cg.mworker, lastTicket.VDFResult)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out, proof, err := vdf.Run(vrfout)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tick := &types.Ticket{
|
||||||
|
VRFProof: vrfout,
|
||||||
|
VDFProof: proof,
|
||||||
|
VDFResult: out,
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
miner, proof, tickets, err := cg.nextBlockProof()
|
miner, proof, tickets, err := cg.nextBlockProof(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -199,7 +231,7 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := cg.w.Sign(cg.banker, unsigned)
|
sig, err := cg.w.Sign(context.TODO(), cg.banker, unsigned)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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,17 +138,132 @@ 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
|
||||||
|
|
||||||
state, err := MakeInitialStateTree(bs, balances)
|
// 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, xerrors.Errorf("failed to create NewVM: %w", 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)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UGLY HACKY MODIFICATION OF MINER POWER
|
||||||
|
|
||||||
|
// we have to flush the vm here because it buffers stuff internally for perf reasons
|
||||||
|
if _, err := vm.Flush(ctx); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("vm.Flush failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
st := vm.StateTree()
|
||||||
|
mact, err := st.GetActor(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("get miner actor failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cst := hamt.CSTFromBstore(cs.Blockstore())
|
||||||
|
var mstate actors.StorageMinerActorState
|
||||||
|
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
|
||||||
|
return cid.Undef, xerrors.Errorf("getting miner actor state failed: %w", 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 {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
||||||
|
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
stateroot, err := state.Flush()
|
stateroot, err := state.Flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("flush state tree failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// temp chainstore
|
||||||
|
cs := store.NewChainStore(bs, datastore.NewMapDatastore())
|
||||||
|
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, gmcfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cst := hamt.CSTFromBstore(bs)
|
cst := hamt.CSTFromBstore(bs)
|
||||||
@ -162,9 +282,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,
|
||||||
@ -187,3 +313,19 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
|
|||||||
Genesis: b,
|
Genesis: b,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SignFunc func(context.Context, address.Address, []byte) (*types.Signature, error)
|
||||||
|
|
||||||
|
func ComputeVRF(ctx context.Context, sign SignFunc, w address.Address, input []byte) ([]byte, error) {
|
||||||
|
|
||||||
|
sig, err := sign(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
|
||||||
|
}
|
||||||
|
106
chain/sync.go
106
chain/sync.go
@ -8,9 +8,11 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"github.com/filecoin-project/go-lotus/chain/store"
|
"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"
|
"github.com/filecoin-project/go-lotus/chain/vm"
|
||||||
|
"github.com/filecoin-project/go-lotus/lib/vdf"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
dstore "github.com/ipfs/go-datastore"
|
dstore "github.com/ipfs/go-datastore"
|
||||||
@ -287,7 +289,7 @@ func (syncer *Syncer) Sync(maybeHead *store.FullTipSet) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := syncer.collectChain(maybeHead); err != nil {
|
if err := syncer.collectChain(maybeHead); err != nil {
|
||||||
return err
|
return xerrors.Errorf("collectChain failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syncer.store.PutTipSet(maybeHead); err != nil {
|
if err := syncer.store.PutTipSet(maybeHead); err != nil {
|
||||||
@ -311,6 +313,89 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, baseTs *types.TipSet) error {
|
||||||
|
var err error
|
||||||
|
enc, err := actors.SerializeParams(&actors.IsMinerParam{Addr: maddr})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := vm.Call(ctx, syncer.store, &types.Message{
|
||||||
|
To: actors.StorageMarketAddress,
|
||||||
|
From: maddr,
|
||||||
|
Method: actors.SMAMethods.IsMiner,
|
||||||
|
Params: enc,
|
||||||
|
}, baseTs)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("checking if block miner is valid failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("StorageMarket.IsMiner check failed (exit code %d)", ret.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ensure the miner is currently not late on their PoSt submission (this hasnt landed in the spec yet)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (syncer *Syncer) validateTickets(ctx context.Context, mworker address.Address, tickets []*types.Ticket, base *types.TipSet) error {
|
||||||
|
if len(tickets) == 0 {
|
||||||
|
return xerrors.Errorf("block had no tickets")
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := base.MinTicket()
|
||||||
|
for i := 0; i < len(tickets); i++ {
|
||||||
|
next := tickets[i]
|
||||||
|
|
||||||
|
sig := &types.Signature{
|
||||||
|
Type: types.KTBLS,
|
||||||
|
Data: next.VRFProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("About to verify signature: ", sig.Data, mworker, cur.VDFResult)
|
||||||
|
if err := sig.Verify(mworker, cur.VDFResult); err != nil {
|
||||||
|
return xerrors.Errorf("invalid ticket, VRFProof invalid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now verify the VDF
|
||||||
|
if err := vdf.Verify(next.VRFProof, next.VDFResult, next.VDFProof); err != nil {
|
||||||
|
return xerrors.Errorf("ticket %d had invalid VDF: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = next
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMinerWorker(ctx context.Context, cs *store.ChainStore, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||||
|
recp, err := vm.CallRaw(ctx, cs, &types.Message{
|
||||||
|
To: maddr,
|
||||||
|
From: maddr,
|
||||||
|
Method: actors.MAMethods.GetWorkerAddr,
|
||||||
|
}, st, 0)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if recp.ExitCode != 0 {
|
||||||
|
return address.Undef, xerrors.Errorf("getting miner worker addr failed (exit code %d)", recp.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
worker, err := address.NewFromBytes(recp.Return)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if worker.Protocol() == address.ID {
|
||||||
|
return address.Undef, xerrors.Errorf("need to resolve worker address to a pubkeyaddr")
|
||||||
|
}
|
||||||
|
|
||||||
|
return worker, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should match up with 'Semantical Validation' in validation.md in the spec
|
||||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
||||||
h := b.Header
|
h := b.Header
|
||||||
stateroot, err := syncer.store.TipSetState(h.Parents)
|
stateroot, err := syncer.store.TipSetState(h.Parents)
|
||||||
@ -318,12 +403,25 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
|||||||
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseTs, err := syncer.store.LoadTipSet(b.Header.Parents)
|
baseTs, err := syncer.store.LoadTipSet(h.Parents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vmi, err := vm.NewVM(stateroot, b.Header.Height, b.Header.Miner, syncer.store)
|
if err := syncer.minerIsValid(ctx, h.Miner, baseTs); err != nil {
|
||||||
|
return xerrors.Errorf("minerIsValid failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
waddr, err := getMinerWorker(ctx, syncer.store, stateroot, h.Miner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getMinerWorker failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syncer.validateTickets(ctx, waddr, h.Tickets, baseTs); err != nil {
|
||||||
|
return xerrors.Errorf("validating block tickets failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmi, err := vm.NewVM(stateroot, h.Height, h.Miner, syncer.store)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -549,7 +647,7 @@ func (syncer *Syncer) collectChain(fts *store.FullTipSet) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := syncer.syncMessagesAndCheckState(headers); err != nil {
|
if err := syncer.syncMessagesAndCheckState(headers); err != nil {
|
||||||
return err
|
return xerrors.Errorf("collectChain syncMessages: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -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)}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -55,6 +55,10 @@ func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *SignedMessage) Cid() cid.Cid {
|
func (m *SignedMessage) Cid() cid.Cid {
|
||||||
|
if m.Signature.Type == KTBLS {
|
||||||
|
return m.Message.Cid()
|
||||||
|
}
|
||||||
|
|
||||||
sb, err := m.ToStorageBlock()
|
sb, err := m.ToStorageBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -89,3 +90,18 @@ func (ts *TipSet) Equals(ots *TipSet) bool {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ts *TipSet) MinTicket() *Ticket {
|
||||||
|
if len(ts.Blocks()) == 0 {
|
||||||
|
panic("tipset has no blocks!")
|
||||||
|
}
|
||||||
|
var minTicket *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
|
||||||
|
}
|
||||||
|
@ -6,19 +6,12 @@ import (
|
|||||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||||
"github.com/filecoin-project/go-lotus/chain/store"
|
"github.com/filecoin-project/go-lotus/chain/store"
|
||||||
"github.com/filecoin-project/go-lotus/chain/types"
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
|
cid "github.com/ipfs/go-cid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Call(ctx context.Context, cs *store.ChainStore, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
|
func CallRaw(ctx context.Context, cs *store.ChainStore, msg *types.Message, bstate cid.Cid, bheight uint64) (*types.MessageReceipt, error) {
|
||||||
if ts == nil {
|
vmi, err := NewVM(bstate, bheight, actors.NetworkAddress, cs)
|
||||||
ts = cs.GetHeaviestTipSet()
|
|
||||||
}
|
|
||||||
state, err := cs.TipSetState(ts.Cids())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
vmi, err := NewVM(state, ts.Height(), ts.Blocks()[0].Miner, cs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||||
}
|
}
|
||||||
@ -56,4 +49,18 @@ func Call(ctx context.Context, cs *store.ChainStore, msg *types.Message, ts *typ
|
|||||||
log.Warnf("chain call failed: %s", ret.ActorErr)
|
log.Warnf("chain call failed: %s", ret.ActorErr)
|
||||||
}
|
}
|
||||||
return &ret.MessageReceipt, nil
|
return &ret.MessageReceipt, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Call(ctx context.Context, cs *store.ChainStore, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
|
||||||
|
if ts == nil {
|
||||||
|
ts = cs.GetHeaviestTipSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := cs.TipSetState(ts.Cids())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallRaw(ctx, cs, msg, state, ts.Height())
|
||||||
}
|
}
|
||||||
|
@ -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,6 +1,7 @@
|
|||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wallet) Sign(addr address.Address, msg []byte) (*types.Signature, error) {
|
func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*types.Signature, error) {
|
||||||
ki, err := w.findKey(addr)
|
ki, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,8 +26,12 @@ var minerStart = &cli.Command{
|
|||||||
|
|
||||||
ctx := ReqContext(cctx)
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
// TODO: this address needs to be the address of an actual miner
|
if !cctx.Args().Present() {
|
||||||
maddr, err := api.WalletDefaultAddress(ctx)
|
return fmt.Errorf("must specify miner actor address to mine for")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: need to pull this from disk or something
|
||||||
|
maddr, err := address.NewFromString(cctx.Args().First())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
|
||||||
|
"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/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"
|
||||||
@ -17,6 +20,12 @@ import (
|
|||||||
var initCmd = &cli.Command{
|
var initCmd = &cli.Command{
|
||||||
Name: "init",
|
Name: "init",
|
||||||
Usage: "Initialize a lotus storage miner repo",
|
Usage: "Initialize a lotus storage miner repo",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "actor",
|
||||||
|
Usage: "specify the address of an already created miner actor",
|
||||||
|
},
|
||||||
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
log.Info("Initializing lotus storage miner")
|
log.Info("Initializing lotus storage miner")
|
||||||
log.Info("Checking if repo exists")
|
log.Info("Checking if repo exists")
|
||||||
@ -77,85 +86,27 @@ var initCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Creating StorageMarket.CreateStorageMiner message")
|
var addr address.Address
|
||||||
|
if act := cctx.String("actor"); act != "" {
|
||||||
|
a, err := address.NewFromString(act)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
defOwner, err := api.WalletDefaultAddress(ctx)
|
if err := configureStorageMiner(ctx, api, a, peerid); err != nil {
|
||||||
if err != nil {
|
return xerrors.Errorf("failed to configure storage miner: %w", err)
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
addr = a
|
||||||
|
} else {
|
||||||
|
a, err := createStorageMiner(ctx, api, peerid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = a
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := api.MpoolGetNonce(ctx, defOwner)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
k, err := api.WalletNew(ctx, types.KTSecp256k1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
collateral := types.NewInt(1000) // TODO: Get this from params
|
|
||||||
|
|
||||||
params, err := actors.SerializeParams(actors.CreateStorageMinerParams{
|
|
||||||
Owner: defOwner,
|
|
||||||
Worker: k,
|
|
||||||
SectorSize: types.NewInt(actors.SectorSize),
|
|
||||||
PeerID: peerid,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
createStorageMinerMsg := types.Message{
|
|
||||||
To: actors.StorageMarketAddress,
|
|
||||||
From: defOwner,
|
|
||||||
|
|
||||||
Nonce: nonce,
|
|
||||||
|
|
||||||
Value: collateral,
|
|
||||||
|
|
||||||
Method: actors.SMAMethods.CreateStorageMiner,
|
|
||||||
Params: params,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned, err := createStorageMinerMsg.Serialize()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Signing StorageMarket.CreateStorageMiner")
|
|
||||||
|
|
||||||
sig, err := api.WalletSign(ctx, defOwner, unsigned)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
signed := &types.SignedMessage{
|
|
||||||
Message: createStorageMinerMsg,
|
|
||||||
Signature: *sig,
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Pushing %s to Mpool", signed.Cid())
|
|
||||||
|
|
||||||
err = api.MpoolPush(ctx, signed)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Waiting for confirmation")
|
|
||||||
|
|
||||||
mw, err := api.ChainWaitMsg(ctx, signed.Cid())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := address.NewFromBytes(mw.Receipt.Return)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("New storage miners address is: %s", addr)
|
|
||||||
|
|
||||||
ds, err := lr.Datastore("/metadata")
|
ds, err := lr.Datastore("/metadata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -170,3 +121,149 @@ var initCmd = &cli.Command{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func configureStorageMiner(ctx context.Context, api api.FullNode, addr address.Address, peerid peer.ID) error {
|
||||||
|
// This really just needs to be an api call at this point...
|
||||||
|
recp, err := api.ChainCall(ctx, &types.Message{
|
||||||
|
To: addr,
|
||||||
|
From: addr,
|
||||||
|
Method: actors.MAMethods.GetWorkerAddr,
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("failed to get worker address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if recp.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("getWorkerAddr returned exit code %d", recp.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
waddr, err := address.NewFromBytes(recp.Return)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getWorkerAddr returned bad address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := actors.SerializeParams(&actors.UpdatePeerIDParams{PeerID: peerid})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce, err := api.MpoolGetNonce(ctx, waddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &types.Message{
|
||||||
|
To: addr,
|
||||||
|
From: waddr,
|
||||||
|
Method: actors.MAMethods.UpdatePeerID,
|
||||||
|
Params: enc,
|
||||||
|
Nonce: nonce,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
GasPrice: types.NewInt(0),
|
||||||
|
GasLimit: types.NewInt(1000),
|
||||||
|
}
|
||||||
|
|
||||||
|
smsg, err := api.WalletSignMessage(ctx, waddr, msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := api.MpoolPush(ctx, smsg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Waiting for message: ", smsg.Cid())
|
||||||
|
ret, err := api.ChainWaitMsg(ctx, smsg.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.Receipt.ExitCode != 0 {
|
||||||
|
return xerrors.Errorf("update peer id message failed with exit code %d", ret.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID) (address.Address, error) {
|
||||||
|
log.Info("Creating StorageMarket.CreateStorageMiner message")
|
||||||
|
|
||||||
|
defOwner, err := api.WalletDefaultAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce, err := api.MpoolGetNonce(ctx, defOwner)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k, err := api.WalletNew(ctx, types.KTSecp256k1)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
collateral := types.NewInt(1000) // TODO: Get this from params
|
||||||
|
|
||||||
|
params, err := actors.SerializeParams(actors.CreateStorageMinerParams{
|
||||||
|
Owner: defOwner,
|
||||||
|
Worker: k,
|
||||||
|
SectorSize: types.NewInt(actors.SectorSize),
|
||||||
|
PeerID: peerid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
createStorageMinerMsg := types.Message{
|
||||||
|
To: actors.StorageMarketAddress,
|
||||||
|
From: defOwner,
|
||||||
|
Nonce: nonce,
|
||||||
|
Value: collateral,
|
||||||
|
|
||||||
|
Method: actors.SMAMethods.CreateStorageMiner,
|
||||||
|
Params: params,
|
||||||
|
|
||||||
|
GasLimit: types.NewInt(10000),
|
||||||
|
GasPrice: types.NewInt(0),
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned, err := createStorageMinerMsg.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Signing StorageMarket.CreateStorageMiner")
|
||||||
|
|
||||||
|
sig, err := api.WalletSign(ctx, defOwner, unsigned)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signed := &types.SignedMessage{
|
||||||
|
Message: createStorageMinerMsg,
|
||||||
|
Signature: *sig,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Pushing %s to Mpool", signed.Cid())
|
||||||
|
|
||||||
|
err = api.MpoolPush(ctx, signed)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Waiting for confirmation")
|
||||||
|
|
||||||
|
mw, err := api.ChainWaitMsg(ctx, signed.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := address.NewFromBytes(mw.Receipt.Return)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("New storage miners address is: %s", addr)
|
||||||
|
return addr, 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-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
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 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=
|
||||||
|
28
lib/vdf/vdf.go
Normal file
28
lib/vdf/vdf.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package vdf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run(input []byte) ([]byte, []byte, error) {
|
||||||
|
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 Verify(input []byte, out []byte, proof []byte) error {
|
||||||
|
// this is a fake VDF
|
||||||
|
h := sha256.Sum256(input)
|
||||||
|
|
||||||
|
if !bytes.Equal(h[:], out) {
|
||||||
|
return fmt.Errorf("vdf output incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(proof, []byte("proof")) {
|
||||||
|
return fmt.Errorf("vdf proof failed to validate")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
153
miner/miner.go
153
miner/miner.go
@ -2,20 +2,28 @@ package miner
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"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/gen"
|
||||||
"github.com/filecoin-project/go-lotus/chain/types"
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/go-lotus/lib/vdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
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,154 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
return gen.ComputeVRF(ctx, m.api.WalletSign, w, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 {
|
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
|
return vdf.Run(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) createBlock(base *MiningBase, ticket types.Ticket, proof types.ElectionProof) (*chain.BlockMsg, error) {
|
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 = base.ts.MinTicket()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
@ -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
|
||||||
@ -326,7 +326,7 @@ func (a *FullNodeAPI) WalletBalance(ctx context.Context, addr address.Address) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *FullNodeAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*types.Signature, error) {
|
func (a *FullNodeAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*types.Signature, error) {
|
||||||
return a.Wallet.Sign(k, msg)
|
return a.Wallet.Sign(ctx, k, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FullNodeAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) {
|
func (a *FullNodeAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) {
|
||||||
|
@ -2,6 +2,7 @@ package testing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -27,7 +28,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,20 +62,27 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("GENESIS MINER ADDRESS: ", gmc.MinerAddr.String())
|
||||||
|
|
||||||
f, err := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY, 0644)
|
f, err := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Loading…
Reference in New Issue
Block a user