initial refactor for creating tipsets with multiple parents
This commit is contained in:
parent
2f03ac000e
commit
6e21372ccb
@ -106,6 +106,7 @@ type FullNode interface {
|
||||
StateMinerSectors(context.Context, address.Address) ([]*SectorInfo, error)
|
||||
StateMinerProvingSet(context.Context, address.Address) ([]*SectorInfo, error)
|
||||
StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error)
|
||||
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
|
||||
PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error)
|
||||
PaychList(context.Context) ([]address.Address, error)
|
||||
|
@ -75,9 +75,10 @@ type FullNodeStruct struct {
|
||||
ClientStartDeal func(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) `perm:"admin"`
|
||||
ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"`
|
||||
|
||||
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
|
||||
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
|
||||
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
|
||||
|
||||
PaychCreate func(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) `perm:"sign"`
|
||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||
@ -283,6 +284,10 @@ func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address,
|
||||
return c.Internal.StateMinerPower(ctx, a, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return c.Internal.StateMinerWorker(ctx, m, ts)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) {
|
||||
return c.Internal.PaychCreate(ctx, from, to, amt)
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ func (bs *BlockSync) processBlocksResponse(req *BlockSyncRequest, res *BlockSync
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cidArrsEqual(cur.Parents(), nts.Cids()) {
|
||||
if !types.CidArrsEqual(cur.Parents(), nts.Cids()) {
|
||||
return nil, fmt.Errorf("parents of tipset[%d] were not tipset[%d]", bi-1, bi)
|
||||
}
|
||||
|
||||
@ -406,18 +406,6 @@ func (bs *BlockSync) processBlocksResponse(req *BlockSyncRequest, res *BlockSync
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func cidArrsEqual(a, b []cid.Cid) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if b[i] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (bs *BlockSync) GetBlock(ctx context.Context, c cid.Cid) (*types.BlockHeader, error) {
|
||||
sb, err := bs.bserv.GetBlock(ctx, c)
|
||||
if err != nil {
|
||||
|
@ -3,6 +3,8 @@ package gen
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ipfs/go-blockservice"
|
||||
@ -11,6 +13,7 @@ import (
|
||||
"github.com/ipfs/go-merkledag"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/api"
|
||||
"github.com/filecoin-project/go-lotus/build"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/store"
|
||||
@ -43,8 +46,8 @@ type ChainGen struct {
|
||||
|
||||
w *wallet.Wallet
|
||||
|
||||
miner address.Address
|
||||
mworker address.Address
|
||||
miners []address.Address
|
||||
mworkers []address.Address
|
||||
receivers []address.Address
|
||||
banker address.Address
|
||||
bankerNonce uint64
|
||||
@ -147,8 +150,8 @@ func NewGenerator() (*ChainGen, error) {
|
||||
genesis: genb.Genesis,
|
||||
w: w,
|
||||
|
||||
miner: minercfg.MinerAddr,
|
||||
mworker: worker,
|
||||
miners: []address.Address{minercfg.MinerAddr},
|
||||
mworkers: []address.Address{worker},
|
||||
banker: banker,
|
||||
receivers: receievers,
|
||||
|
||||
@ -184,7 +187,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context) (address.Address, types.
|
||||
ticks := cg.curBlock.Header.Tickets
|
||||
lastTicket := ticks[len(ticks)-1]
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, cg.w.Sign, cg.mworker, lastTicket.VDFResult)
|
||||
vrfout, err := ComputeVRF(ctx, cg.w.Sign, cg.mworkers[0], lastTicket.VDFResult)
|
||||
if err != nil {
|
||||
return address.Undef, nil, nil, err
|
||||
}
|
||||
@ -200,13 +203,18 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context) (address.Address, types.
|
||||
VDFResult: out,
|
||||
}
|
||||
|
||||
return cg.miner, []byte("cat in a box"), []*types.Ticket{tick}, nil
|
||||
return cg.miners[0], []byte("cat in a box"), []*types.Ticket{tick}, nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error) {
|
||||
type MinedTipSet struct {
|
||||
TipSet *store.FullTipSet
|
||||
Messages []*types.SignedMessage
|
||||
}
|
||||
|
||||
func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
|
||||
miner, proof, tickets, err := cg.nextBlockProof(context.TODO())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// make some transfers from banker
|
||||
@ -229,12 +237,12 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
|
||||
|
||||
unsigned, err := msg.Serialize()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := cg.w.Sign(context.TODO(), cg.banker, unsigned)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs[m] = &types.SignedMessage{
|
||||
@ -243,7 +251,7 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
|
||||
}
|
||||
|
||||
if _, err := cg.cs.PutMessage(msgs[m]); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,23 +259,26 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
|
||||
|
||||
parents, err := types.NewTipSet([]*types.BlockHeader{cg.curBlock.Header})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts := parents.MinTimestamp() + (uint64(len(tickets)) * build.BlockDelay)
|
||||
|
||||
fblk, err := MinerCreateBlock(context.TODO(), cg.cs, cg.w, miner, parents, tickets, proof, msgs, ts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cg.cs.AddBlock(fblk.Header); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cg.curBlock = fblk
|
||||
|
||||
return fblk, msgs, nil
|
||||
return &MinedTipSet{
|
||||
TipSet: store.NewFullTipSet([]*types.FullBlock{fblk}),
|
||||
Messages: msgs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
|
||||
@ -276,3 +287,55 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
|
||||
}
|
||||
return cg.r, nil
|
||||
}
|
||||
|
||||
type MiningCheckAPI interface {
|
||||
ChainGetRandomness(context.Context, *types.TipSet) ([]byte, error)
|
||||
|
||||
StateMinerPower(context.Context, address.Address, *types.TipSet) (api.MinerPower, error)
|
||||
|
||||
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
|
||||
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
|
||||
}
|
||||
|
||||
func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket, miner address.Address, a MiningCheckAPI) (bool, types.ElectionProof, error) {
|
||||
r, err := a.ChainGetRandomness(ctx, ts)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
mworker, err := a.StateMinerWorker(ctx, miner, ts)
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||
}
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, a.WalletSign, mworker, r)
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
|
||||
pow, err := a.StateMinerPower(ctx, miner, ts)
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("failed to check power: %w", err)
|
||||
}
|
||||
|
||||
return PowerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil
|
||||
}
|
||||
|
||||
func PowerCmp(vrfout []byte, mpow, totpow types.BigInt) bool {
|
||||
|
||||
/*
|
||||
Need to check that
|
||||
h(vrfout) / 2^256 < minerPower / totalPower
|
||||
*/
|
||||
|
||||
h := sha256.Sum256(vrfout)
|
||||
|
||||
// 2^256
|
||||
rden := types.BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)}
|
||||
|
||||
top := types.BigMul(rden, mpow)
|
||||
out := types.BigDiv(top, totpow)
|
||||
|
||||
return types.BigCmp(types.BigFromBytes(h[:]), out) < 0
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ func testGeneration(t testing.TB, n int, msgs int) {
|
||||
g.msgsPerBlock = msgs
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
b, _, err := g.NextBlock()
|
||||
mts, err := g.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatalf("error at H:%d, %s", i, err)
|
||||
}
|
||||
if b.Header.Height != uint64(i+1) {
|
||||
if mts.TipSet.TipSet().Height() != uint64(i+1) {
|
||||
t.Fatal("wrong height")
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/state"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
@ -35,6 +36,9 @@ type ChainStore struct {
|
||||
|
||||
bestTips *pubsub.PubSub
|
||||
|
||||
tstLk sync.Mutex
|
||||
tipsets map[uint64][]cid.Cid
|
||||
|
||||
headChangeNotifs []func(rev, app []*types.TipSet) error
|
||||
}
|
||||
|
||||
@ -43,6 +47,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore {
|
||||
bs: bs,
|
||||
ds: ds,
|
||||
bestTips: pubsub.New(64),
|
||||
tipsets: make(map[uint64][]cid.Cid),
|
||||
}
|
||||
|
||||
hcnf := func(rev, app []*types.TipSet) error {
|
||||
@ -317,12 +322,35 @@ func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
|
||||
return cs.heaviest
|
||||
}
|
||||
|
||||
func (cs *ChainStore) addToTipSetTracker(b *types.BlockHeader) error {
|
||||
cs.tstLk.Lock()
|
||||
defer cs.tstLk.Unlock()
|
||||
|
||||
tss := cs.tipsets[b.Height]
|
||||
for _, oc := range tss {
|
||||
if oc == b.Cid() {
|
||||
log.Warn("tried to add block to tipset tracker that was already there")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
cs.tipsets[b.Height] = append(tss, b.Cid())
|
||||
|
||||
// TODO: do we want to look for slashable submissions here? might as well...
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) PersistBlockHeader(b *types.BlockHeader) error {
|
||||
sb, err := b.ToStorageBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cs.addToTipSetTracker(b); err != nil {
|
||||
return xerrors.Errorf("failed to insert new block (%s) into tipset tracker: %w", b.Cid(), err)
|
||||
}
|
||||
|
||||
return cs.bs.Put(sb)
|
||||
}
|
||||
|
||||
@ -365,12 +393,49 @@ func (cs *ChainStore) PutMessage(m storable) (cid.Cid, error) {
|
||||
return PutMessage(cs.bs, m)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) expandTipset(b *types.BlockHeader) (*types.TipSet, error) {
|
||||
// Hold lock for the whole function for now, if it becomes a problem we can
|
||||
// fix pretty easily
|
||||
cs.tstLk.Lock()
|
||||
defer cs.tstLk.Unlock()
|
||||
|
||||
all := []*types.BlockHeader{b}
|
||||
|
||||
tsets, ok := cs.tipsets[b.Height]
|
||||
if !ok {
|
||||
return types.NewTipSet(all)
|
||||
}
|
||||
|
||||
for _, bhc := range tsets {
|
||||
if bhc == b.Cid() {
|
||||
continue
|
||||
}
|
||||
|
||||
h, err := cs.GetBlock(bhc)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load block (%s) for tipset expansion: %w", bhc, err)
|
||||
}
|
||||
|
||||
if types.CidArrsEqual(h.Parents, b.Parents) {
|
||||
all = append(all, h)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: other validation...?
|
||||
|
||||
return types.NewTipSet(all)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) AddBlock(b *types.BlockHeader) error {
|
||||
if err := cs.PersistBlockHeader(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ts, _ := types.NewTipSet([]*types.BlockHeader{b})
|
||||
ts, err := cs.expandTipset(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cs.MaybeTakeHeavierTipSet(ts); err != nil {
|
||||
return errors.Wrap(err, "MaybeTakeHeavierTipSet failed")
|
||||
}
|
||||
|
@ -562,7 +562,7 @@ func (syncer *Syncer) collectHeaders(from *types.TipSet, to *types.TipSet) ([]*t
|
||||
at = blks[len(blks)-1].Parents()
|
||||
}
|
||||
|
||||
if !cidArrsEqual(blockSet[len(blockSet)-1].Parents(), to.Cids()) {
|
||||
if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents(), to.Cids()) {
|
||||
// TODO: handle the case where we are on a fork and its not a simple fast forward
|
||||
return nil, xerrors.Errorf("synced header chain does not link to our best block")
|
||||
}
|
||||
|
@ -12,26 +12,28 @@ import (
|
||||
"github.com/filecoin-project/go-lotus/api"
|
||||
"github.com/filecoin-project/go-lotus/chain"
|
||||
"github.com/filecoin-project/go-lotus/chain/gen"
|
||||
"github.com/filecoin-project/go-lotus/chain/store"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/node"
|
||||
"github.com/filecoin-project/go-lotus/node/impl"
|
||||
"github.com/filecoin-project/go-lotus/node/modules"
|
||||
"github.com/filecoin-project/go-lotus/node/repo"
|
||||
)
|
||||
|
||||
const source = 0
|
||||
|
||||
func (tu *syncTestUtil) repoWithChain(t testing.TB, h int) (repo.Repo, []byte, []*types.FullBlock) {
|
||||
blks := make([]*types.FullBlock, h)
|
||||
func (tu *syncTestUtil) repoWithChain(t testing.TB, h int) (repo.Repo, []byte, []*store.FullTipSet) {
|
||||
blks := make([]*store.FullTipSet, h)
|
||||
|
||||
for i := 0; i < h; i++ {
|
||||
var err error
|
||||
blks[i], _, err = tu.g.NextBlock()
|
||||
mts, err := tu.g.NextTipSet()
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("block at H:%d: %s\n", blks[i].Header.Height, blks[i].Cid())
|
||||
blks[i] = mts.TipSet
|
||||
|
||||
require.Equal(t, uint64(i+1), blks[i].Header.Height, "wrong height")
|
||||
ts := mts.TipSet.TipSet()
|
||||
fmt.Printf("tipset at H:%d: %s\n", ts.Height(), ts.Cids())
|
||||
|
||||
require.Equal(t, uint64(i+1), ts.Height(), "wrong height")
|
||||
}
|
||||
|
||||
r, err := tu.g.YieldRepo()
|
||||
@ -54,7 +56,7 @@ type syncTestUtil struct {
|
||||
g *gen.ChainGen
|
||||
|
||||
genesis []byte
|
||||
blocks []*types.FullBlock
|
||||
blocks []*store.FullTipSet
|
||||
|
||||
nds []api.FullNode
|
||||
}
|
||||
@ -92,14 +94,16 @@ func (tu *syncTestUtil) Shutdown() {
|
||||
}
|
||||
|
||||
func (tu *syncTestUtil) mineNewBlock(src int) {
|
||||
fblk, msgs, err := tu.g.NextBlock()
|
||||
mts, err := tu.g.NextTipSet()
|
||||
require.NoError(tu.t, err)
|
||||
|
||||
for _, msg := range msgs {
|
||||
for _, msg := range mts.Messages {
|
||||
require.NoError(tu.t, tu.nds[src].MpoolPush(context.TODO(), msg))
|
||||
}
|
||||
|
||||
require.NoError(tu.t, tu.nds[src].ChainSubmitBlock(context.TODO(), fblkToBlkMsg(fblk)))
|
||||
for _, fblk := range mts.TipSet.Blocks {
|
||||
require.NoError(tu.t, tu.nds[src].ChainSubmitBlock(context.TODO(), fblkToBlkMsg(fblk)))
|
||||
}
|
||||
}
|
||||
|
||||
func fblkToBlkMsg(fb *types.FullBlock) *chain.BlockMsg {
|
||||
@ -215,6 +219,7 @@ func (tu *syncTestUtil) waitUntilSync(from, to int) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func (tu *syncTestUtil) submitSourceBlock(to int, h int) {
|
||||
// utility to simulate incoming blocks without miner process
|
||||
// TODO: should call syncer directly, this won't work correctly in all cases
|
||||
@ -238,6 +243,7 @@ func (tu *syncTestUtil) submitSourceBlocks(to int, h int, n int) {
|
||||
tu.submitSourceBlock(to, h+i)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func TestSyncSimple(t *testing.T) {
|
||||
H := 50
|
||||
@ -256,7 +262,7 @@ func TestSyncSimple(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncMining(t *testing.T) {
|
||||
H := 100
|
||||
H := 50
|
||||
tu := prepSyncTest(t, H)
|
||||
|
||||
client := tu.addClientNode()
|
||||
|
@ -114,3 +114,15 @@ func (mm *MsgMeta) ToStorageBlock() (block.Block, error) {
|
||||
|
||||
return block.NewBlockWithCid(buf.Bytes(), c)
|
||||
}
|
||||
|
||||
func CidArrsEqual(a, b []cid.Cid) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if b[i] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package miner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -200,7 +198,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(ctx, base)
|
||||
win, proof, err := gen.IsRoundWinner(ctx, base.ts, base.tickets, m.addresses[0], &m.api)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to check if we win next round")
|
||||
}
|
||||
@ -255,43 +253,6 @@ func (m *Miner) getMinerWorker(ctx context.Context, addr address.Address, ts *ty
|
||||
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
|
||||
}
|
||||
|
||||
vrfout, err := m.computeVRF(ctx, r)
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
|
||||
pow, err := m.api.StateMinerPower(ctx, m.addresses[0], base.ts)
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("failed to check power: %w", err)
|
||||
}
|
||||
|
||||
return powerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil
|
||||
}
|
||||
|
||||
func powerCmp(vrfout []byte, mpow, totpow types.BigInt) bool {
|
||||
|
||||
/*
|
||||
Need to check that
|
||||
h(vrfout) / 2^256 < minerPower / totalPower
|
||||
*/
|
||||
|
||||
h := sha256.Sum256(vrfout)
|
||||
|
||||
// 2^256
|
||||
rden := types.BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)}
|
||||
|
||||
top := types.BigMul(rden, mpow)
|
||||
out := types.BigDiv(top, totpow)
|
||||
|
||||
return types.BigCmp(types.BigFromBytes(h[:]), out) < 0
|
||||
}
|
||||
|
||||
func (m *Miner) runVDF(ctx context.Context, input []byte) ([]byte, []byte, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
@ -3,10 +3,11 @@ package full
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/chain/vm"
|
||||
"golang.org/x/xerrors"
|
||||
"strconv"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/api"
|
||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||
@ -186,3 +187,25 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, t
|
||||
TotalPower: tpow,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
ret, err := vm.Call(ctx, a.Chain, &types.Message{
|
||||
From: m,
|
||||
To: m,
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user