lotus/node/impl/paych/paych.go

258 lines
6.5 KiB
Go
Raw Normal View History

2019-09-16 13:46:05 +00:00
package paych
2019-08-20 16:48:33 +00:00
import (
"context"
"fmt"
2020-02-13 03:50:37 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
2019-09-16 13:46:05 +00:00
"github.com/ipfs/go-cid"
"go.uber.org/fx"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
full "github.com/filecoin-project/lotus/node/impl/full"
"github.com/filecoin-project/lotus/paychmgr"
2019-08-20 16:48:33 +00:00
)
type PaychAPI struct {
fx.In
2019-09-16 13:46:05 +00:00
full.MpoolAPI
full.WalletAPI
full.ChainAPI
2019-08-20 16:48:33 +00:00
PaychMgr *paychmgr.Manager
2019-08-20 16:48:33 +00:00
}
2019-09-16 13:46:05 +00:00
func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*api.ChannelInfo, error) {
ch, mcid, err := a.PaychMgr.GetPaych(ctx, from, to, ensureFunds)
2019-08-20 16:48:33 +00:00
if err != nil {
return nil, err
2019-08-20 16:48:33 +00:00
}
return &api.ChannelInfo{
2019-09-16 13:46:05 +00:00
Channel: ch,
ChannelMessage: mcid,
}, nil
}
2019-09-16 13:46:05 +00:00
func (a *PaychAPI) PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error) {
return a.PaychMgr.AllocateLane(ch)
}
2019-09-24 21:13:47 +00:00
func (a *PaychAPI) PaychNewPayment(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) {
amount := vouchers[len(vouchers)-1].Amount
2019-09-16 17:23:48 +00:00
// TODO: Fix free fund tracking in PaychGet
2019-09-24 21:13:47 +00:00
// TODO: validate voucher spec before locking funds
2019-09-16 17:23:48 +00:00
ch, err := a.PaychGet(ctx, from, to, amount)
if err != nil {
return nil, err
}
2019-09-16 13:46:05 +00:00
lane, err := a.PaychMgr.AllocateLane(ch.Channel)
if err != nil {
return nil, err
}
2019-09-24 21:13:47 +00:00
svs := make([]*types.SignedVoucher, len(vouchers))
2019-09-24 21:13:47 +00:00
for i, v := range vouchers {
sv, err := a.paychVoucherCreate(ctx, ch.Channel, types.SignedVoucher{
Amount: v.Amount,
Lane: lane,
2020-02-13 03:50:37 +00:00
Extra: v.Extra,
TimeLock: v.TimeLock,
MinSettleHeight: v.MinSettle,
2019-09-24 21:13:47 +00:00
})
if err != nil {
return nil, err
}
svs[i] = sv
}
2019-09-24 21:13:47 +00:00
var pchCid *cid.Cid
if ch.ChannelMessage != cid.Undef {
pchCid = &ch.ChannelMessage
}
return &api.PaymentInfo{
2019-09-16 13:46:05 +00:00
Channel: ch.Channel,
ChannelMessage: pchCid,
2019-09-24 21:13:47 +00:00
Vouchers: svs,
}, nil
2019-08-20 16:48:33 +00:00
}
func (a *PaychAPI) PaychList(ctx context.Context) ([]address.Address, error) {
return a.PaychMgr.ListChannels()
}
func (a *PaychAPI) PaychStatus(ctx context.Context, pch address.Address) (*api.PaychStatus, error) {
2019-09-06 22:39:47 +00:00
ci, err := a.PaychMgr.GetChannelInfo(pch)
if err != nil {
return nil, err
}
return &api.PaychStatus{
ControlAddr: ci.Control,
2019-09-06 22:39:47 +00:00
Direction: api.PCHDir(ci.Direction),
}, nil
2019-08-20 16:48:33 +00:00
}
func (a *PaychAPI) PaychClose(ctx context.Context, addr address.Address) (cid.Cid, error) {
2020-02-13 03:50:37 +00:00
panic("TODO Settle logic")
2019-08-20 16:48:33 +00:00
ci, err := a.PaychMgr.GetChannelInfo(addr)
if err != nil {
return cid.Undef, err
}
nonce, err := a.MpoolGetNonce(ctx, ci.Control)
2019-08-20 16:48:33 +00:00
if err != nil {
return cid.Undef, err
}
msg := &types.Message{
To: addr,
From: ci.Control,
2019-08-20 16:48:33 +00:00
Value: types.NewInt(0),
2020-02-13 03:50:37 +00:00
Method: builtin.MethodsPaych.Settle,
2019-08-20 16:48:33 +00:00
Nonce: nonce,
GasLimit: types.NewInt(500),
GasPrice: types.NewInt(0),
}
smsg, err := a.WalletSignMessage(ctx, ci.Control, msg)
2019-08-20 16:48:33 +00:00
if err != nil {
return cid.Undef, err
}
2020-01-07 19:52:17 +00:00
if _, err := a.MpoolPush(ctx, smsg); err != nil {
2019-08-20 16:48:33 +00:00
return cid.Undef, err
}
return smsg.Cid(), nil
}
func (a *PaychAPI) PaychVoucherCheckValid(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
return a.PaychMgr.CheckVoucherValid(ctx, ch, sv)
}
func (a *PaychAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, sv *types.SignedVoucher, secret []byte, proof []byte) (bool, error) {
return a.PaychMgr.CheckVoucherSpendable(ctx, ch, sv, secret, proof)
}
2019-09-16 21:25:23 +00:00
func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *types.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
2019-09-09 13:59:07 +00:00
_ = a.PaychMgr.TrackInboundChannel(ctx, ch) // TODO: expose those calls
2019-09-06 22:39:47 +00:00
2019-09-16 21:25:23 +00:00
return a.PaychMgr.AddVoucher(ctx, ch, sv, proof, minDelta)
2019-08-20 16:48:33 +00:00
}
// PaychVoucherCreate creates a new signed voucher on the given payment channel
// with the given lane and amount. The value passed in is exactly the value
// that will be used to create the voucher, so if previous vouchers exist, the
// actual additional value of this voucher will only be the difference between
// the two.
func (a *PaychAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {
return a.paychVoucherCreate(ctx, pch, types.SignedVoucher{Amount: amt, Lane: lane})
}
func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address, voucher types.SignedVoucher) (*types.SignedVoucher, error) {
ci, err := a.PaychMgr.GetChannelInfo(pch)
if err != nil {
2019-11-04 19:03:11 +00:00
return nil, xerrors.Errorf("get channel info: %w", err)
2019-08-20 16:48:33 +00:00
}
nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, voucher.Lane)
if err != nil {
2019-11-04 19:03:11 +00:00
return nil, xerrors.Errorf("getting next nonce for lane: %w", err)
2019-08-20 16:48:33 +00:00
}
sv := &voucher
sv.Nonce = nonce
vb, err := sv.SigningBytes()
if err != nil {
return nil, err
}
sig, err := a.WalletSign(ctx, ci.Control, vb)
2019-08-20 16:48:33 +00:00
if err != nil {
return nil, err
}
sv.Signature = sig
2019-09-16 21:25:23 +00:00
if _, err := a.PaychMgr.AddVoucher(ctx, pch, sv, nil, types.NewInt(0)); err != nil {
2019-08-20 16:48:33 +00:00
return nil, xerrors.Errorf("failed to persist voucher: %w", err)
}
return sv, nil
}
func (a *PaychAPI) PaychVoucherList(ctx context.Context, pch address.Address) ([]*types.SignedVoucher, error) {
2019-09-09 13:59:07 +00:00
vi, err := a.PaychMgr.ListVouchers(ctx, pch)
if err != nil {
return nil, err
}
out := make([]*types.SignedVoucher, len(vi))
for k, v := range vi {
out[k] = v.Voucher
}
return out, nil
2019-08-20 16:48:33 +00:00
}
func (a *PaychAPI) PaychVoucherSubmit(ctx context.Context, ch address.Address, sv *types.SignedVoucher) (cid.Cid, error) {
ci, err := a.PaychMgr.GetChannelInfo(ch)
if err != nil {
return cid.Undef, err
}
nonce, err := a.MpoolGetNonce(ctx, ci.Control)
2019-08-20 16:48:33 +00:00
if err != nil {
return cid.Undef, err
}
if sv.Extra != nil || len(sv.SecretPreimage) > 0 {
return cid.Undef, fmt.Errorf("cant handle more advanced payment channel stuff yet")
}
2020-02-13 03:50:37 +00:00
enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{
2019-08-20 16:48:33 +00:00
Sv: *sv,
})
if err != nil {
return cid.Undef, err
}
msg := &types.Message{
From: ci.Control,
2019-08-20 16:48:33 +00:00
To: ch,
Value: types.NewInt(0),
Nonce: nonce,
2020-02-13 03:50:37 +00:00
Method: builtin.MethodsPaych.UpdateChannelState,
2019-08-20 16:48:33 +00:00
Params: enc,
GasLimit: types.NewInt(100000),
GasPrice: types.NewInt(0),
}
smsg, err := a.WalletSignMessage(ctx, ci.Control, msg)
2019-08-20 16:48:33 +00:00
if err != nil {
return cid.Undef, err
}
2020-01-07 19:52:17 +00:00
if _, err := a.MpoolPush(ctx, smsg); err != nil {
2019-08-20 16:48:33 +00:00
return cid.Undef, err
}
// TODO: should we wait for it...?
return smsg.Cid(), nil
}