lotus/chain/market/fundmgr.go
2020-02-23 16:50:36 +01:00

88 lines
1.9 KiB
Go

package market
import (
"context"
"sync"
"github.com/filecoin-project/specs-actors/actors/builtin"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/impl/full"
)
type FundMgr struct {
sm *stmgr.StateManager
mpool full.MpoolAPI
lk sync.Mutex
available map[address.Address]types.BigInt
}
func NewFundMgr(sm *stmgr.StateManager, mpool full.MpoolAPI) *FundMgr {
return &FundMgr{
sm: sm,
mpool: mpool,
available: map[address.Address]types.BigInt{},
}
}
func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr address.Address, amt types.BigInt) error {
fm.lk.Lock()
avail, ok := fm.available[addr]
if !ok {
bal, err := fm.sm.MarketBalance(ctx, addr, nil)
if err != nil {
fm.lk.Unlock()
return err
}
avail = types.BigSub(bal.Escrow, bal.Locked)
}
toAdd := types.NewInt(0)
avail = types.BigSub(avail, amt)
if avail.LessThan(types.NewInt(0)) {
// TODO: some rules around adding more to avoid doing stuff on-chain
// all the time
toAdd = types.BigSub(toAdd, avail)
avail = types.NewInt(0)
}
fm.available[addr] = avail
fm.lk.Unlock()
var err error
params, err := actors.SerializeParams(&addr)
if err != nil {
return err
}
smsg, err := fm.mpool.MpoolPushMessage(ctx, &types.Message{
To: actors.StorageMarketAddress,
From: addr,
Value: toAdd,
GasPrice: types.NewInt(0),
GasLimit: types.NewInt(1000000),
Method: builtin.MethodsMarket.AddBalance,
Params: params,
})
if err != nil {
return err
}
_, r, err := fm.sm.WaitForMessage(ctx, smsg.Cid())
if err != nil {
return err
}
if r.ExitCode != 0 {
return xerrors.Errorf("adding funds to storage miner market actor failed: exit %d", r.ExitCode)
}
return nil
}