Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: actor overview #123

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion documentation/en/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ git checkout <release version>
3. By default, a ‘multicore-sdr’ option is used in the proofs library. This feature is also used in FFI unless explicitly disabled. To disable building with the ‘multicore-sdr’ dependency, set `FFI_USE_MULTICORE_SDR` to `0`:\


```shell
```shell
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will misalign the docs.

Screenshot 2024-08-15 at 12 48 41 PM

export FFI_USE_MULTICORE_SDR=0
```
4. Build and install Curio:\
Expand Down
134 changes: 112 additions & 22 deletions web/api/webrpc/actor_summary.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package webrpc

import (
"bytes"
"context"
"sort"

"golang.org/x/xerrors"

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"

"github.com/filecoin-project/curio/deps/config"
"github.com/filecoin-project/curio/lib/curiochain"

"github.com/filecoin-project/lotus/blockstore"
Expand Down Expand Up @@ -39,78 +42,164 @@ type ActorDeadline struct {
}

type minimalActorInfo struct {
Addresses []struct {
MinerAddresses []string
}
Addresses []config.CurioAddresses
}

func (a *WebRPC) ActorSummary(ctx context.Context) ([]ActorSummary, error) {
stor := store.ActorStore(ctx, blockstore.NewReadCachedBlockstore(blockstore.NewAPIBlockstore(a.deps.Chain), curiochain.ChainBlockCache))
type WalletInfo struct {
Type string
Address string
Balance string
}
type ActorDetail struct {
Summary ActorSummary
Wallets []WalletInfo
}

var actorInfos []ActorSummary
func (a *WebRPC) ActorDetail(ctx context.Context, ActorIDstr string) (*ActorDetail, error) {
in, err := address.NewFromString(ActorIDstr)
if err != nil {
return nil, xerrors.Errorf("parsing address: %w", err)
}
confNameToAddr := map[address.Address][]string{}
minerWallets := map[string][]address.Address{}
err = a.visitAddresses(func(layer string, aset config.CurioAddresses, a address.Address) {
if !bytes.Equal(in.Bytes(), a.Bytes()) {
return
}
for name, aset := range map[string][]string{
layer + ":Commit": aset.PreCommitControl,
layer + ":Control": aset.CommitControl,
layer + ":Terminate": aset.TerminateControl,
} {
for _, addr := range aset {
a, err := address.NewFromString(addr)
if err != nil {
log.Errorf("parsing address: %w", err)
continue
}
minerWallets[name] = append(minerWallets[name], a)
}
}
confNameToAddr[a] = append(confNameToAddr[a], layer)
})
if err != nil {
return nil, xerrors.Errorf("visiting addresses: %w", err)
}

asAry, balanceCache, err := a.getActorSummary(ctx, confNameToAddr)
if err != nil || len(asAry) == 0 {
return nil, xerrors.Errorf("getting actor summary: %w, len()=%d", err, len(asAry))
}
ad := ActorDetail{
Summary: asAry[0],
Wallets: []WalletInfo{},
}

// minerWallets := map[string][]address.Address{}
for name, addrs := range minerWallets {
for _, addr := range addrs {
wb, ok := balanceCache[addr]
if !ok {
wb, err = a.deps.Chain.WalletBalance(ctx, addr)
if err != nil {
return nil, xerrors.Errorf("getting wallet balance: %w", err)
}
balanceCache[addr] = wb
}
ad.Wallets = append(ad.Wallets, WalletInfo{
Type: name,
Address: addr.String(),
Balance: types.FIL(wb).String(),
})
}
}
return &ad, nil
}

func (a *WebRPC) ActorSummary(ctx context.Context) ([]ActorSummary, error) {
confNameToAddr := map[address.Address][]string{}
err := a.visitAddresses(func(name string, _ config.CurioAddresses, a address.Address) {
confNameToAddr[a] = append(confNameToAddr[a], name)
})
if err != nil {
return nil, err
}
as, _, err := a.getActorSummary(ctx, confNameToAddr)
return as, err
}

func (a *WebRPC) visitAddresses(cb func(string, config.CurioAddresses, address.Address)) error {
err := forEachConfig(a, func(name string, info minimalActorInfo) error {
for _, aset := range info.Addresses {
for _, addr := range aset.MinerAddresses {
a, err := address.NewFromString(addr)
if err != nil {
return xerrors.Errorf("parsing address: %w", err)
}
confNameToAddr[a] = append(confNameToAddr[a], name)
cb(name, aset, a)
}
}
return nil
})
if err != nil {
return nil, err
return nil
}
return nil
}

func (a *WebRPC) getActorSummary(ctx context.Context, confNameToAddr map[address.Address][]string) (as []ActorSummary, balanceCache map[address.Address]big.Int, err error) {
wins, err := a.spWins(ctx)
if err != nil {
return nil, xerrors.Errorf("getting sp wins: %w", err)
return nil, nil, xerrors.Errorf("getting sp wins: %w", err)
}
balanceCache = map[address.Address]big.Int{}

stor := store.ActorStore(ctx,
blockstore.NewReadCachedBlockstore(blockstore.NewAPIBlockstore(a.deps.Chain), curiochain.ChainBlockCache))
var actorInfos []ActorSummary

for addr, cnames := range confNameToAddr {
p, err := a.deps.Chain.StateMinerPower(ctx, addr, types.EmptyTSK)
if err != nil {
return nil, xerrors.Errorf("getting miner power: %w", err)
return nil, nil, xerrors.Errorf("getting miner power: %w", err)
}

mact, err := a.deps.Chain.StateGetActor(ctx, addr, types.EmptyTSK)
if err != nil {
return nil, xerrors.Errorf("getting actor: %w", err)
return nil, nil, xerrors.Errorf("getting actor: %w", err)
}

mas, err := miner.Load(stor, mact)
if err != nil {
return nil, err
return nil, nil, err
}

deadlines, err := a.getDeadlines(ctx, addr)
if err != nil {
return nil, err
return nil, nil, err
}

avail, err := mas.AvailableBalance(mact.Balance)
if err != nil {
return nil, xerrors.Errorf("getting available balance: %w", err)
return nil, nil, xerrors.Errorf("getting available balance: %w", err)
}

mi, err := mas.Info()
if err != nil {
return nil, xerrors.Errorf("getting miner info: %w", err)
return nil, nil, xerrors.Errorf("getting miner info: %w", err)
}

wbal, err := a.deps.Chain.WalletBalance(ctx, mi.Worker)
if err != nil {
return nil, xerrors.Errorf("getting worker balance: %w", err)
wbal, ok := balanceCache[mi.Worker]
if !ok {
wbal, err = a.deps.Chain.WalletBalance(ctx, mi.Worker)
if err != nil {
return nil, nil, xerrors.Errorf("getting worker balance: %w", err)
}
balanceCache[mi.Worker] = wbal
}

sort.Strings(cnames)

actorInfos = append(actorInfos, ActorSummary{
as := ActorSummary{
Address: addr.String(),
CLayers: cnames,
QualityAdjustedPower: types.DeciStr(p.MinerPower.QualityAdjPower),
Expand All @@ -122,14 +211,15 @@ func (a *WebRPC) ActorSummary(ctx context.Context) ([]ActorSummary, error) {
Win1: wins[addr].Win1,
Win7: wins[addr].Win7,
Win30: wins[addr].Win30,
})
}
actorInfos = append(actorInfos, as)
}

sort.Slice(actorInfos, func(i, j int) bool {
return actorInfos[i].Address < actorInfos[j].Address
})

return actorInfos, nil
return actorInfos, balanceCache, nil
}

func (a *WebRPC) getDeadlines(ctx context.Context, addr address.Address) ([]ActorDeadline, error) {
Expand Down
13 changes: 12 additions & 1 deletion web/static/actor-summary.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { LitElement, html, css } from 'https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js';
import RPCCall from '/lib/jsonrpc.mjs';
import '/lib/clipboard-copy.mjs';

class Expirations extends LitElement {
static properties = {
Expand Down Expand Up @@ -184,6 +185,11 @@ class ActorSummary extends LitElement {
.deadline-faulty {
background-color: red;
}

.address-container {
display: flex;
align-items: center;
}
`;

constructor() {
Expand Down Expand Up @@ -249,7 +255,12 @@ class ActorSummary extends LitElement {
<tbody>
${this.data.map(entry => html`
<tr>
<td>${entry.Address}</td>
<td>
<div class="address-container">
<a href="/actor/?id=${entry.Address}">${entry.Address}</a>
<clipboard-copy .text=${entry.Address}></clipboard-copy>
</div>
</td>
<td>
${entry.CLayers.map(layer => html`<span>${layer} </span>`)}
</td>
Expand Down
Loading