Skip to content

Commit

Permalink
Merge pull request #5025 from filecoin-project/feat/accounting-tool
Browse files Browse the repository at this point in the history
add a tooling to make filecoin accounting a little easier
  • Loading branch information
magik6k authored Nov 27, 2020
2 parents aa27844 + 61485be commit 0c1592f
Showing 1 changed file with 121 additions and 0 deletions.
121 changes: 121 additions & 0 deletions cmd/lotus-shed/balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package main

import (
"context"
"encoding/csv"
"fmt"
"io"
"os"
"strconv"
"strings"
"time"

"github.com/filecoin-project/lotus/chain/gen/genesis"

Expand Down Expand Up @@ -62,6 +66,7 @@ var auditsCmd = &cli.Command{
chainBalanceCmd,
chainBalanceStateCmd,
chainPledgeCmd,
fillBalancesCmd,
},
}

Expand Down Expand Up @@ -487,3 +492,119 @@ var chainPledgeCmd = &cli.Command{
return nil
},
}

const dateFmt = "1/02/06"

func parseCsv(inp string) ([]time.Time, []address.Address, error) {
fi, err := os.Open(inp)
if err != nil {
return nil, nil, err
}

r := csv.NewReader(fi)
recs, err := r.ReadAll()
if err != nil {
return nil, nil, err
}

var addrs []address.Address
for _, rec := range recs[1:] {
a, err := address.NewFromString(rec[0])
if err != nil {
return nil, nil, err
}
addrs = append(addrs, a)
}

var dates []time.Time
for _, d := range recs[0][1:] {
if len(d) == 0 {
continue
}
p := strings.Split(d, " ")
t, err := time.Parse(dateFmt, p[len(p)-1])
if err != nil {
return nil, nil, err
}

dates = append(dates, t)
}

return dates, addrs, nil
}

func heightForDate(d time.Time, ts *types.TipSet) abi.ChainEpoch {
secs := d.Unix()
gents := ts.Blocks()[0].Timestamp
gents -= uint64(30 * ts.Height())
return abi.ChainEpoch((secs - int64(gents)) / 30)
}

var fillBalancesCmd = &cli.Command{
Name: "fill-balances",
Description: "fill out balances for addresses on dates in given spreadsheet",
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}

defer closer()
ctx := lcli.ReqContext(cctx)

dates, addrs, err := parseCsv(cctx.Args().First())
if err != nil {
return err
}

ts, err := api.ChainHead(ctx)
if err != nil {
return err
}

var tipsets []*types.TipSet
for _, d := range dates {
h := heightForDate(d, ts)
hts, err := api.ChainGetTipSetByHeight(ctx, h, ts.Key())
if err != nil {
return err
}
tipsets = append(tipsets, hts)
}

var balances [][]abi.TokenAmount
for _, a := range addrs {
var b []abi.TokenAmount
for _, hts := range tipsets {
act, err := api.StateGetActor(ctx, a, hts.Key())
if err != nil {
if !strings.Contains(err.Error(), "actor not found") {
return fmt.Errorf("error for %s at %s: %w", a, hts.Key(), err)
}
b = append(b, types.NewInt(0))
continue
}
b = append(b, act.Balance)
}
balances = append(balances, b)
}

var datestrs []string
for _, d := range dates {
datestrs = append(datestrs, "Balance at "+d.Format(dateFmt))
}

w := csv.NewWriter(os.Stdout)
w.Write(append([]string{"Wallet Address"}, datestrs...)) // nolint:errcheck
for i := 0; i < len(addrs); i++ {
row := []string{addrs[i].String()}
for _, b := range balances[i] {
row = append(row, types.FIL(b).String())
}
w.Write(row) // nolint:errcheck
}
w.Flush()
return nil
},
}

0 comments on commit 0c1592f

Please sign in to comment.