lotus/cmd/lotus-shed/genesis-verify.go
2020-11-03 23:44:44 +01:00

178 lines
4.5 KiB
Go

package main
import (
"context"
"fmt"
"os"
"sort"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/fatih/color"
"github.com/ipfs/go-datastore"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin/account"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/blockstore"
)
type addrInfo struct {
Key address.Address
Balance types.FIL
}
type msigInfo struct {
Signers []address.Address
Balance types.FIL
Threshold uint64
}
type minerInfo struct {
}
var genesisVerifyCmd = &cli.Command{
Name: "verify-genesis",
Description: "verify some basic attributes of a genesis car file",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("must pass genesis car file")
}
bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), nil, nil)
cf := cctx.Args().Get(0)
f, err := os.Open(cf)
if err != nil {
return xerrors.Errorf("opening the car file: %w", err)
}
ts, err := cs.Import(f)
if err != nil {
return err
}
sm := stmgr.NewStateManager(cs)
total, err := stmgr.CheckTotalFIL(context.TODO(), sm, ts)
if err != nil {
return err
}
fmt.Println("Genesis: ", ts.Key())
expFIL := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision)))
fmt.Printf("Total FIL: %s", types.FIL(total))
if !expFIL.Equals(total) {
color.Red(" INCORRECT!")
}
fmt.Println()
cst := cbor.NewCborStore(bs)
stree, err := state.LoadStateTree(cst, ts.ParentState())
if err != nil {
return err
}
var accAddrs, msigAddrs []address.Address
kaccounts := make(map[address.Address]addrInfo)
kmultisigs := make(map[address.Address]msigInfo)
kminers := make(map[address.Address]minerInfo)
ctx := context.TODO()
store := adt.WrapStore(ctx, cst)
if err := stree.ForEach(func(addr address.Address, act *types.Actor) error {
switch {
case builtin.IsStorageMinerActor(act.Code):
_, err := miner.Load(store, act)
if err != nil {
return xerrors.Errorf("miner actor: %w", err)
}
// TODO: actually verify something here?
kminers[addr] = minerInfo{}
case builtin.IsMultisigActor(act.Code):
st, err := multisig.Load(store, act)
if err != nil {
return xerrors.Errorf("multisig actor: %w", err)
}
signers, err := st.Signers()
if err != nil {
return xerrors.Errorf("multisig actor: %w", err)
}
threshold, err := st.Threshold()
if err != nil {
return xerrors.Errorf("multisig actor: %w", err)
}
kmultisigs[addr] = msigInfo{
Balance: types.FIL(act.Balance),
Signers: signers,
Threshold: threshold,
}
msigAddrs = append(msigAddrs, addr)
case builtin.IsAccountActor(act.Code):
st, err := account.Load(store, act)
if err != nil {
// TODO: magik6k: this _used_ to log instead of failing, why?
return xerrors.Errorf("account actor %s: %w", addr, err)
}
pkaddr, err := st.PubkeyAddress()
if err != nil {
return xerrors.Errorf("failed to get actor pk address %s: %w", addr, err)
}
kaccounts[addr] = addrInfo{
Key: pkaddr,
Balance: types.FIL(act.Balance.Copy()),
}
accAddrs = append(accAddrs, addr)
}
return nil
}); err != nil {
return err
}
sort.Slice(accAddrs, func(i, j int) bool {
return accAddrs[i].String() < accAddrs[j].String()
})
sort.Slice(msigAddrs, func(i, j int) bool {
return msigAddrs[i].String() < msigAddrs[j].String()
})
fmt.Println("Account Actors:")
for _, acc := range accAddrs {
a := kaccounts[acc]
fmt.Printf("%s\t%s\t%s\n", acc, a.Key, a.Balance)
}
fmt.Println("Multisig Actors:")
for _, acc := range msigAddrs {
m := kmultisigs[acc]
fmt.Printf("%s\t%s\t%d\t[", acc, m.Balance, m.Threshold)
for i, s := range m.Signers {
fmt.Print(s)
if i != len(m.Signers)-1 {
fmt.Print(",")
}
}
fmt.Printf("]\n")
}
return nil
},
}