diff --git a/api/api.go b/api/api.go index 53475384f..33b6626fd 100644 --- a/api/api.go +++ b/api/api.go @@ -67,6 +67,7 @@ type FullNode interface { MinerRegister(context.Context, address.Address) error MinerUnregister(context.Context, address.Address) error + MinerAddresses(context.Context) ([]address.Address, error) MinerCreateBlock(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) // // UX ? @@ -97,6 +98,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) PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) PaychList(context.Context) ([]address.Address, error) @@ -171,3 +173,8 @@ type ActorState struct { } type PaychStatus struct{} + +type MinerPower struct { + MinerPower types.BigInt + TotalPower types.BigInt +} diff --git a/api/struct.go b/api/struct.go index 433144bee..51607a2d7 100644 --- a/api/struct.go +++ b/api/struct.go @@ -56,6 +56,7 @@ type FullNodeStruct struct { MinerRegister func(context.Context, address.Address) error `perm:"admin"` MinerUnregister func(context.Context, address.Address) error `perm:"admin"` + MinerAddresses func(context.Context) ([]address.Address, error) `perm:"write"` MinerCreateBlock func(context.Context, address.Address, *types.TipSet, []*types.Ticket, types.ElectionProof, []*types.SignedMessage) (*chain.BlockMsg, error) `perm:"write"` WalletNew func(context.Context, string) (address.Address, error) `perm:"write"` @@ -71,8 +72,9 @@ type FullNodeStruct struct { ClientListImports func(ctx context.Context) ([]Import, error) `perm:"read"` ClientStartDeal func(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) `perm:"admin"` - StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` - StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, 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"` 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"` @@ -168,6 +170,10 @@ func (c *FullNodeStruct) MinerUnregister(ctx context.Context, addr address.Addre return c.Internal.MinerUnregister(ctx, addr) } +func (c *FullNodeStruct) MinerAddresses(ctx context.Context) ([]address.Address, error) { + return c.Internal.MinerAddresses(ctx) +} + func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, tickets []*types.Ticket, eproof types.ElectionProof, msgs []*types.SignedMessage) (*chain.BlockMsg, error) { return c.Internal.MinerCreateBlock(ctx, addr, base, tickets, eproof, msgs) } @@ -256,6 +262,10 @@ func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address. return c.Internal.StateMinerProvingSet(ctx, addr) } +func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, ts *types.TipSet) (MinerPower, error) { + return c.Internal.StateMinerPower(ctx, a, 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) } diff --git a/chain/types/tipset.go b/chain/types/tipset.go index e42cca01c..661f2d4e9 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -6,8 +6,11 @@ import ( "fmt" "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log" ) +var log = logging.Logger("types") + type TipSet struct { cids []cid.Cid blks []*BlockHeader @@ -65,8 +68,10 @@ func (ts *TipSet) Height() uint64 { return ts.height } -func (ts *TipSet) Weight() uint64 { - panic("if tipsets are going to have weight on them, we need to wire that through") +func (ts *TipSet) Weight() BigInt { + // TODO: implement correctly + log.Warn("Called TipSet.Weight: TODO: correct implementation") + return BigAdd(ts.blks[0].ParentWeight, NewInt(1)) } func (ts *TipSet) Parents() []cid.Cid { diff --git a/cli/state.go b/cli/state.go index 9f1f8851b..ce799093f 100644 --- a/cli/state.go +++ b/cli/state.go @@ -2,13 +2,10 @@ package cli import ( "fmt" - "math/big" "gopkg.in/urfave/cli.v2" - "github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/address" - types "github.com/filecoin-project/go-lotus/chain/types" ) var stateCmd = &cli.Command{ @@ -32,43 +29,24 @@ var statePowerCmd = &cli.Command{ ctx := ReqContext(cctx) - var msg *types.Message + var maddr address.Address if cctx.Args().Present() { - maddr, err := address.NewFromString(cctx.Args().First()) + maddr, err = address.NewFromString(cctx.Args().First()) if err != nil { return err } - - enc, err := actors.SerializeParams(&actors.PowerLookupParams{ - Miner: maddr, - }) - if err != nil { - return err - } - - msg = &types.Message{ - To: actors.StorageMarketAddress, - From: actors.StorageMarketAddress, - Method: actors.SMAMethods.PowerLookup, - Params: enc, - } - } else { - msg = &types.Message{ - To: actors.StorageMarketAddress, - From: actors.StorageMarketAddress, - Method: actors.SMAMethods.GetTotalStorage, - } } - ret, err := api.ChainCall(ctx, msg, nil) + power, err := api.StateMinerPower(ctx, maddr, nil) if err != nil { return err } - if ret.ExitCode != 0 { - return fmt.Errorf("call to get power failed: %d", ret.ExitCode) + + res := power.TotalPower + if cctx.Args().Present() { + res = power.MinerPower } - v := big.NewInt(0).SetBytes(ret.Return) - fmt.Println(v.String()) + fmt.Println(res.String()) return nil }, } diff --git a/cmd/lotus-storage-miner/init.go b/cmd/lotus-storage-miner/init.go index 047624563..0567f51b0 100644 --- a/cmd/lotus-storage-miner/init.go +++ b/cmd/lotus-storage-miner/init.go @@ -217,7 +217,7 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID) ( return address.Undef, err } - k, err := api.WalletNew(ctx, types.KTSecp256k1) + k, err := api.WalletNew(ctx, types.KTBLS) if err != nil { return address.Undef, err } diff --git a/lotuspond/api.go b/lotuspond/api.go index be01921a7..321e0b0e1 100644 --- a/lotuspond/api.go +++ b/lotuspond/api.go @@ -149,8 +149,13 @@ func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) { return nodeInfo{}, err } + initArgs := []string{"init"} + if fullNodeRepo == api.running[1].meta.Repo { + initArgs = []string{"init", "--actor=t0101", "--genesis-miner"} + } + id := atomic.AddInt32(&api.cmds, 1) - cmd := exec.Command("./lotus-storage-miner", "init") + cmd := exec.Command("./lotus-storage-miner", initArgs...) cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile) cmd.Stdout = io.MultiWriter(os.Stdout, logfile) cmd.Env = []string{"LOTUS_STORAGE_PATH=" + dir, "LOTUS_PATH=" + fullNodeRepo} diff --git a/lotuspond/front/src/Address.js b/lotuspond/front/src/Address.js index 96d89a0ad..7cb9e373b 100644 --- a/lotuspond/front/src/Address.js +++ b/lotuspond/front/src/Address.js @@ -31,17 +31,21 @@ class Address extends React.Component { let balance = 0 let actor = {} let actorInfo + let minerInfo try { balance = await this.props.client.call('Filecoin.WalletBalance', [this.props.addr]) actor = await this.props.client.call('Filecoin.ChainGetActor', [this.props.addr, this.props.ts || null]) actorInfo = await this.actorInfo(actor) + if(this.props.miner) { + minerInfo = await this.props.client.call('Filecoin.StateMinerPower', [this.props.addr, this.props.ts || null]) + } } catch (err) { console.log(err) balance = -1 } - this.setState({balance, actor, actorInfo}) + this.setState({balance, actor, actorInfo, minerInfo}) } openState() { @@ -94,7 +98,12 @@ class Address extends React.Component { transfer =  {this.props.transfer}FIL } - return {addr}{balance}{actInfo}{add1k}{transfer} + let minerInfo = + if(this.state.minerInfo) { + minerInfo =  Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%) + } + + return {addr}{balance}{actInfo}{add1k}{transfer}{minerInfo} } } diff --git a/lotuspond/front/src/FullNode.js b/lotuspond/front/src/FullNode.js index a53990cea..09dc12b96 100644 --- a/lotuspond/front/src/FullNode.js +++ b/lotuspond/front/src/FullNode.js @@ -10,13 +10,11 @@ class FullNode extends React.Component { constructor(props) { super(props) - this.state = { - mining: false, - } + this.state = {} this.loadInfo = this.loadInfo.bind(this) - this.startMining = this.startMining.bind(this) - this.newScepAddr = this.newScepAddr.bind(this) + this.newSecpAddr = this.newSecpAddr.bind(this) + this.newBLSAddr = this.newBLSAddr.bind(this) this.startStorageMiner = this.startStorageMiner.bind(this) this.add1k = this.add1k.bind(this) this.explorer = this.explorer.bind(this) @@ -46,6 +44,8 @@ class FullNode extends React.Component { return this.props.client.call('Filecoin.PaychVoucherList', [paych]) })) + let minerList = await this.props.client.call('Filecoin.MinerAddresses', []) + this.setState(() => ({ id: id, version: version, @@ -56,28 +56,24 @@ class FullNode extends React.Component { paychs: paychs, vouchers: vouchers, - defaultAddr: defaultAddr})) + defaultAddr: defaultAddr, + + minerList: minerList, + })) } - async startMining() { - // TODO: Use actual miner address - // see cli/miner.go - this.setState({mining: true}) - let addr = "t0101" // in case we have no wallets - /*if (this.state.defaultAddr) { - addr = this.state.defaultAddr - }*/ - - this.setState({mining: true}) - await this.props.client.call("Filecoin.MinerStart", [addr]) - } - - async newScepAddr() { + async newSecpAddr() { const t = "secp256k1" await this.props.client.call("Filecoin.WalletNew", [t]) this.loadInfo() } + async newBLSAddr() { + const t = "bls" + await this.props.client.call("Filecoin.WalletNew", [t]) + this.loadInfo() + } + async startStorageMiner() { this.props.mountWindow((onClose) => ) } @@ -105,9 +101,9 @@ class FullNode extends React.Component { ) } - let mine = [Mine] - if (this.state.mining) { - mine = "[Mining]" + let miners = + if(this.state.minerList.length > 0) { + miners = this.state.minerList.map((a, k) =>
) } let storageMine = [Spawn Storage Miner] @@ -143,11 +139,12 @@ class FullNode extends React.Component {
Repo: LOTUS_PATH={this.props.node.Repo}
{chainInfo}
- {mine} {storageMine} + {storageMine}
-
Balances: [New [Secp256k1]]
+
Balances: [New [Secp256k1] [BLS]]
{addresses}
+
{miners}
{paychannels}
diff --git a/miner/miner.go b/miner/miner.go index 7bbcccf44..d8ff1455b 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -30,6 +30,7 @@ type api struct { full.ChainAPI full.MpoolAPI full.WalletAPI + full.StateAPI } func NewMiner(api api) *Miner { @@ -53,6 +54,16 @@ type Miner struct { lastWork *MiningBase } +func (m *Miner) Addresses() ([]address.Address, error) { + m.lk.Lock() + defer m.lk.Unlock() + + out := make([]address.Address, len(m.addresses)) + copy(out, m.addresses) + + return out, nil +} + func (m *Miner) Register(addr address.Address) error { m.lk.Lock() defer m.lk.Unlock() @@ -171,7 +182,7 @@ func (m *Miner) GetBestMiningCandidate() (*MiningBase, error) { return m.lastWork, nil } - if bts.Weight() <= m.lastWork.ts.Weight() { + if types.BigCmp(bts.Weight(), m.lastWork.ts.Weight()) <= 0 { return m.lastWork, nil } } @@ -254,12 +265,12 @@ func (m *Miner) isWinnerNextRound(ctx context.Context, base *MiningBase) (bool, return false, nil, xerrors.Errorf("failed to compute VRF: %w", err) } - mpow, totpow, err := m.getPowerForTipset(ctx, m.addresses[0], base.ts) + 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, mpow, totpow), vrfout, nil + return powerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil } func powerCmp(vrfout []byte, mpow, totpow types.BigInt) bool { @@ -280,45 +291,6 @@ func powerCmp(vrfout []byte, mpow, totpow types.BigInt) bool { 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(): diff --git a/node/impl/full.go b/node/impl/full.go index 03bd5d7d7..c8c788064 100644 --- a/node/impl/full.go +++ b/node/impl/full.go @@ -24,6 +24,10 @@ type FullNodeAPI struct { Miner *miner.Miner } +func (a *FullNodeAPI) MinerAddresses(context.Context) ([]address.Address, error) { + return a.Miner.Addresses() +} + func (a *FullNodeAPI) MinerRegister(ctx context.Context, addr address.Address) error { return a.Miner.Register(addr) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 5a557948b..bcf518837 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -3,6 +3,9 @@ package full import ( "context" "fmt" + "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" @@ -137,3 +140,49 @@ func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Addres }) return sinfos, nil } + +func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) { + var err error + enc, err := actors.SerializeParams(&actors.PowerLookupParams{maddr}) + if err != nil { + return api.MinerPower{}, err + } + + var mpow types.BigInt + + if maddr != address.Undef { + ret, err := vm.Call(ctx, a.Chain, &types.Message{ + From: maddr, + To: actors.StorageMarketAddress, + Method: actors.SMAMethods.PowerLookup, + Params: enc, + }, ts) + if err != nil { + return api.MinerPower{}, xerrors.Errorf("failed to get miner power from chain: %w", err) + } + if ret.ExitCode != 0 { + return api.MinerPower{}, xerrors.Errorf("failed to get miner power from chain (exit code %d)", ret.ExitCode) + } + + mpow = types.BigFromBytes(ret.Return) + } + + ret, err := vm.Call(ctx, a.Chain, &types.Message{ + From: actors.StorageMarketAddress, + To: actors.StorageMarketAddress, + Method: actors.SMAMethods.GetTotalStorage, + }, ts) + if err != nil { + return api.MinerPower{}, xerrors.Errorf("failed to get total power from chain: %w", err) + } + if ret.ExitCode != 0 { + return api.MinerPower{}, xerrors.Errorf("failed to get total power from chain (exit code %d)", ret.ExitCode) + } + + tpow := types.BigFromBytes(ret.Return) + + return api.MinerPower{ + MinerPower: mpow, + TotalPower: tpow, + }, nil +}