Skip to content

Commit

Permalink
Add an endpoint for precise circularting supply
Browse files Browse the repository at this point in the history
  • Loading branch information
arajasek committed Oct 6, 2020
1 parent 0e2f697 commit c938424
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 25 deletions.
6 changes: 5 additions & 1 deletion api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,12 @@ type FullNode interface {
// can issue. It takes the deal size and verified status as parameters.
StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error)

// StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset
// StateCirculatingSupply returns an approximation of the circulating supply of Filecoin at the given tipset.
// This is the value used by the protocol when calculating pledge collateral.
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
// StateExactCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset.
// This is not used anywhere in the protocol itself, and is only for external consumption.
StateExactCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error)
// StateNetworkVersion returns the network version at the given tipset
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)

Expand Down
5 changes: 5 additions & 0 deletions api/apistruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ type FullNodeStruct struct {
StateVerifiedRegistryRootKey func(ctx context.Context, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
StateExactCirculatingSupply func(context.Context, types.TipSetKey) (abi.TokenAmount, error) `perm:"read"`
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`

MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
Expand Down Expand Up @@ -925,6 +926,10 @@ func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.T
return c.Internal.StateCirculatingSupply(ctx, tsk)
}

func (c *FullNodeStruct) StateExactCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
return c.Internal.StateExactCirculatingSupply(ctx, tsk)
}

func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) {
return c.Internal.StateNetworkVersion(ctx, tsk)
}
Expand Down
19 changes: 19 additions & 0 deletions chain/actors/builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package builtin
import (
"fmt"

builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"

"github.com/filecoin-project/go-address"

"github.com/filecoin-project/go-state-types/abi"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
Expand All @@ -12,6 +16,12 @@ import (
"github.com/filecoin-project/go-state-types/network"
)

var SystemActorAddr = builtin0.SystemActorAddr
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
var CronActorAddr = builtin0.CronActorAddr
var SaftAddress = makeAddress("t0122")
var ReserveAddress = makeAddress("t090")

type Version int

const (
Expand Down Expand Up @@ -41,3 +51,12 @@ func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate {
func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower {
return miner0.QAPowerForWeight(size, duration, dealWeight, verifiedWeight)
}

func makeAddress(addr string) address.Address {
ret, err := address.NewFromString(addr)
if err != nil {
panic(err)
}

return ret
}
5 changes: 5 additions & 0 deletions chain/actors/builtin/miner/miner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package miner

import (
"github.com/filecoin-project/go-state-types/big"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
Expand Down Expand Up @@ -171,3 +172,7 @@ type LockedFunds struct {
InitialPledgeRequirement abi.TokenAmount
PreCommitDeposits abi.TokenAmount
}

func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount {
return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits))
}
12 changes: 10 additions & 2 deletions chain/actors/builtin/miner/v0.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@ type partition0 struct {
store adt.Store
}

func (s *state0) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
return s.GetAvailableBalance(bal), nil
func (s *state0) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
defer func() {
if r := recover(); r != nil {
err = xerrors.Errorf("failed to get available balance: %w", r)
available = abi.NewTokenAmount(0)
}
}()
// this panics if the miner doesnt have enough funds to cover their locked pledge
available = s.GetAvailableBalance(bal)
return available, err
}

func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
Expand Down
21 changes: 9 additions & 12 deletions chain/stmgr/forks.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"encoding/binary"
"math"

"github.com/filecoin-project/lotus/chain/actors/builtin"

multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"

"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
Expand Down Expand Up @@ -150,11 +152,6 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
}

ReserveAddress, err := address.NewFromString("t090")
if err != nil {
return cid.Undef, xerrors.Errorf("failed to parse reserve address: %w", err)
}

tree, err := sm.StateTree(root)
if err != nil {
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
Expand All @@ -180,7 +177,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
if !sysAcc {
transfers = append(transfers, transfer{
From: addr,
To: ReserveAddress,
To: builtin.ReserveAddress,
Amt: act.Balance,
})
}
Expand All @@ -204,7 +201,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal

transfers = append(transfers, transfer{
From: addr,
To: ReserveAddress,
To: builtin.ReserveAddress,
Amt: available,
})
}
Expand Down Expand Up @@ -255,7 +252,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
nbalance := big.Min(prevBalance, AccountCap)
if nbalance.Sign() != 0 {
transfersBack = append(transfersBack, transfer{
From: ReserveAddress,
From: builtin.ReserveAddress,
To: addr,
Amt: nbalance,
})
Expand All @@ -282,7 +279,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal

mfunds := minerFundsAlloc(power, totalPower)
transfersBack = append(transfersBack, transfer{
From: ReserveAddress,
From: builtin.ReserveAddress,
To: minfo.Worker,
Amt: mfunds,
})
Expand All @@ -302,7 +299,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal

if lbsectors.Length() > 0 {
transfersBack = append(transfersBack, transfer{
From: ReserveAddress,
From: builtin.ReserveAddress,
To: minfo.Worker,
Amt: BaseMinerBalance,
})
Expand All @@ -329,7 +326,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
if err != nil {
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
}
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance); err != nil {
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
}

Expand All @@ -345,7 +342,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
}

difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
if err := doTransfer(cb, tree, ReserveAddress, reimbAddr, difference); err != nil {
if err := doTransfer(cb, tree, builtin.ReserveAddress, reimbAddr, difference); err != nil {
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
}

Expand Down
91 changes: 91 additions & 0 deletions chain/stmgr/stmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import (
"fmt"
"sync"

"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"

_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"

"github.com/filecoin-project/lotus/chain/actors/builtin/miner"

builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"

Expand Down Expand Up @@ -1257,6 +1263,91 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
return csi.FilCirculating, nil
}

func (sm *StateManager) GetExactCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
circ := big.Zero()
unCirc := big.Zero()
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
switch {
case a == _init.Address ||
a == reward.Address ||
a == verifreg.Address ||
// The power actor itself should never receive funds
a == power.Address ||
a == builtin.SystemActorAddr ||
a == builtin.CronActorAddr ||
a == builtin.BurntFundsActorAddr ||
a == builtin.SaftAddress ||
a == builtin.ReserveAddress:

unCirc = big.Add(unCirc, actor.Balance)

case a == market.Address:
mst, err := market.Load(sm.cs.Store(ctx), actor)
if err != nil {
return err
}

lb, err := mst.TotalLocked()
if err != nil {
return err
}

circ = big.Add(circ, big.Sub(actor.Balance, lb))
unCirc = big.Add(unCirc, lb)

case actor.IsAccountActor() || actor.IsPaymentChannelActor():
circ = big.Add(circ, actor.Balance)

case actor.IsStorageMinerActor():
mst, err := miner.Load(sm.cs.Store(ctx), actor)
if err != nil {
return err
}

ab, err := mst.AvailableBalance(actor.Balance)

if err == nil {
circ = big.Add(circ, ab)
unCirc = big.Add(unCirc, big.Sub(actor.Balance, ab))
} else {
// Assume any error is because the miner state is "broken" (lower actor balance than locked funds)
// In this case, the actor's entire balance is considered "uncirculating"
unCirc = big.Add(unCirc, actor.Balance)
}

case actor.IsMultisigActor():
mst, err := multisig.Load(sm.cs.Store(ctx), actor)
if err != nil {
return err
}

lb, err := mst.LockedBalance(height)
if err != nil {
return err
}

ab := big.Sub(actor.Balance, lb)
circ = big.Add(circ, big.Max(ab, big.Zero()))
unCirc = big.Add(unCirc, big.Min(actor.Balance, lb))
default:
return xerrors.Errorf("unexpected actor: %s", a)
}

return nil
})

if err != nil {
return types.EmptyInt, err
}

total := big.Add(circ, unCirc)
if !total.Equals(types.TotalFilecoinInt) {
return types.EmptyInt, xerrors.Errorf("total filecoin didn't add to expected amount: %s != %s", total, types.TotalFilecoinInt)
}

return circ, nil
}

func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
// TODO: move hard fork epoch checks to a schedule defined in build/

Expand Down
37 changes: 27 additions & 10 deletions cli/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,14 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er

var stateCircSupplyCmd = &cli.Command{
Name: "circulating-supply",
Usage: "Get the current circulating supply of filecoin",
Usage: "Get the exact current circulating supply of Filecoin",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "vm-supply",
Usage: "calculates the approximation of the circulating supply used internally by the VM (instead of the exact amount)",
Value: false,
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
Expand All @@ -1623,16 +1630,26 @@ var stateCircSupplyCmd = &cli.Command{
return err
}

circ, err := api.StateCirculatingSupply(ctx, ts.Key())
if err != nil {
return err
}
if cctx.IsSet("vm-supply") {
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
if err != nil {
return err
}

fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
fmt.Println("Mined: ", types.FIL(circ.FilMined))
fmt.Println("Vested: ", types.FIL(circ.FilVested))
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
} else {
circ, err := api.StateExactCirculatingSupply(ctx, ts.Key())
if err != nil {
return err
}

fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
fmt.Println("Mined: ", types.FIL(circ.FilMined))
fmt.Println("Vested: ", types.FIL(circ.FilVested))
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
fmt.Println("Exact circulating supply: ", types.FIL(circ))
return nil
}

return nil
},
Expand Down
24 changes: 24 additions & 0 deletions documentation/en/api-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
* [StateCirculatingSupply](#StateCirculatingSupply)
* [StateCompute](#StateCompute)
* [StateDealProviderCollateralBounds](#StateDealProviderCollateralBounds)
* [StateExactCirculatingSupply](#StateExactCirculatingSupply)
* [StateGetActor](#StateGetActor)
* [StateGetReceipt](#StateGetReceipt)
* [StateListActors](#StateListActors)
Expand Down Expand Up @@ -3100,6 +3101,29 @@ Response:
}
```

### StateExactCirculatingSupply
TODO: Remove StateCirculatingSupply maybe?
StateExactCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset


Perms: read

Inputs:
```json
[
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
{
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
}
]
]
```

Response: `"0"`

### StateGetActor
StateGetActor returns the indicated actor's nonce and balance.

Expand Down
Loading

0 comments on commit c938424

Please sign in to comment.