lotus/paychmgr/simple.go

128 lines
3.5 KiB
Go
Raw Normal View History

package paychmgr
2019-09-16 13:46:05 +00:00
import (
"bytes"
2019-09-16 13:46:05 +00:00
"context"
"fmt"
2020-02-12 23:52:19 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
2019-09-16 13:46:05 +00:00
"github.com/ipfs/go-cid"
2019-12-01 21:52:24 +00:00
"golang.org/x/xerrors"
2019-09-16 13:46:05 +00:00
"github.com/filecoin-project/go-address"
2020-02-12 23:52:19 +00:00
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
2019-09-16 13:46:05 +00:00
)
func (pm *Manager) createPaych(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, cid.Cid, error) {
params, aerr := actors.SerializeParams(&paych.ConstructorParams{From: from, To: to})
2019-09-16 13:46:05 +00:00
if aerr != nil {
return address.Undef, cid.Undef, aerr
}
2020-02-12 23:52:19 +00:00
enc, aerr := actors.SerializeParams(&init_.ExecParams{
2020-02-25 20:54:58 +00:00
CodeCID: builtin.PaymentChannelActorCodeID,
2020-02-12 23:52:19 +00:00
ConstructorParams: params,
2019-09-16 13:46:05 +00:00
})
2019-09-17 08:15:26 +00:00
if aerr != nil {
return address.Undef, cid.Undef, aerr
}
2019-09-16 13:46:05 +00:00
msg := &types.Message{
2020-02-25 20:54:58 +00:00
To: builtin.InitActorAddr,
2019-09-16 13:46:05 +00:00
From: from,
Value: amt,
2020-02-12 23:52:19 +00:00
Method: builtin.MethodsInit.Exec,
2019-09-16 13:46:05 +00:00
Params: enc,
GasLimit: types.NewInt(1000000),
GasPrice: types.NewInt(0),
}
2019-09-17 08:15:26 +00:00
smsg, err := pm.mpool.MpoolPushMessage(ctx, msg)
2019-09-16 13:46:05 +00:00
if err != nil {
2019-12-01 21:52:24 +00:00
return address.Undef, cid.Undef, xerrors.Errorf("initializing paych actor: %w", err)
2019-09-16 13:46:05 +00:00
}
mcid := smsg.Cid()
// TODO: wait outside the store lock!
// (tricky because we need to setup channel tracking before we know it's address)
mwait, err := pm.state.StateWaitMsg(ctx, mcid)
2019-09-16 13:46:05 +00:00
if err != nil {
2019-12-01 21:52:24 +00:00
return address.Undef, cid.Undef, xerrors.Errorf("wait msg: %w", err)
2019-09-16 13:46:05 +00:00
}
if mwait.Receipt.ExitCode != 0 {
return address.Undef, cid.Undef, fmt.Errorf("payment channel creation failed (exit code %d)", mwait.Receipt.ExitCode)
}
var decodedReturn init_.ExecReturn
err = decodedReturn.UnmarshalCBOR(bytes.NewReader(mwait.Receipt.Return))
2019-09-16 13:46:05 +00:00
if err != nil {
return address.Undef, cid.Undef, err
}
paychaddr := decodedReturn.RobustAddress
2019-09-16 13:46:05 +00:00
2019-09-16 17:23:48 +00:00
ci, err := pm.loadOutboundChannelInfo(ctx, paychaddr)
if err != nil {
2019-12-01 21:52:24 +00:00
return address.Undef, cid.Undef, xerrors.Errorf("loading channel info: %w", err)
2019-09-16 17:23:48 +00:00
}
if err := pm.store.trackChannel(ci); err != nil {
2019-12-01 21:52:24 +00:00
return address.Undef, cid.Undef, xerrors.Errorf("tracking channel: %w", err)
2019-09-16 13:46:05 +00:00
}
return paychaddr, mcid, nil
}
func (pm *Manager) addFunds(ctx context.Context, ch address.Address, from address.Address, amt types.BigInt) error {
msg := &types.Message{
To: ch,
From: from,
Value: amt,
Method: 0,
GasLimit: types.NewInt(1000000),
GasPrice: types.NewInt(0),
}
2019-09-17 08:15:26 +00:00
smsg, err := pm.mpool.MpoolPushMessage(ctx, msg)
2019-09-16 13:46:05 +00:00
if err != nil {
return err
}
mwait, err := pm.state.StateWaitMsg(ctx, smsg.Cid()) // TODO: wait outside the store lock!
2019-09-16 13:46:05 +00:00
if err != nil {
return err
}
if mwait.Receipt.ExitCode != 0 {
return fmt.Errorf("voucher channel creation failed: adding funds (exit code %d)", mwait.Receipt.ExitCode)
}
return nil
}
func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, ensureFree types.BigInt) (address.Address, cid.Cid, error) {
pm.store.lk.Lock()
defer pm.store.lk.Unlock()
ch, err := pm.store.findChan(func(ci *ChannelInfo) bool {
if ci.Direction != DirOutbound {
return false
}
return ci.Control == from && ci.Target == to
})
if err != nil {
2019-12-01 21:52:24 +00:00
return address.Undef, cid.Undef, xerrors.Errorf("findChan: %w", err)
2019-09-16 13:46:05 +00:00
}
if ch != address.Undef {
// TODO: Track available funds
return ch, cid.Undef, pm.addFunds(ctx, ch, from, ensureFree)
}
return pm.createPaych(ctx, from, to, ensureFree)
}