lotus/paychmgr/settler/settler.go

140 lines
4.4 KiB
Go
Raw Normal View History

package settler
import (
"context"
"sync"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
2022-06-14 15:00:51 +00:00
"go.uber.org/fx"
"github.com/filecoin-project/go-address"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
2022-04-20 21:34:28 +00:00
"github.com/filecoin-project/go-state-types/builtin"
paychtypes "github.com/filecoin-project/go-state-types/builtin/v8/paych"
2020-09-21 23:01:29 +00:00
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/impl/full"
payapi "github.com/filecoin-project/lotus/node/impl/paych"
2021-02-02 17:43:49 +00:00
"github.com/filecoin-project/lotus/node/modules/helpers"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/lotus/paychmgr"
)
var log = logging.Logger("payment-channel-settler")
// API are the dependencies need to run the payment channel settler
type API struct {
fx.In
full.ChainAPI
full.StateAPI
payapi.PaychAPI
}
type settlerAPI interface {
PaychList(context.Context) ([]address.Address, error)
PaychStatus(context.Context, address.Address) (*api.PaychStatus, error)
2022-04-20 21:34:28 +00:00
PaychVoucherCheckSpendable(context.Context, address.Address, *paychtypes.SignedVoucher, []byte, []byte) (bool, error)
PaychVoucherList(context.Context, address.Address) ([]*paychtypes.SignedVoucher, error)
PaychVoucherSubmit(context.Context, address.Address, *paychtypes.SignedVoucher, []byte, []byte) (cid.Cid, error)
2021-04-03 11:20:50 +00:00
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error)
}
type paymentChannelSettler struct {
ctx context.Context
api settlerAPI
}
// SettlePaymentChannels checks the chain for events related to payment channels settling and
// submits any vouchers for inbound channels tracked for this node
2021-04-05 11:23:46 +00:00
func SettlePaymentChannels(mctx helpers.MetricsCtx, lc fx.Lifecycle, papi API) error {
2021-02-02 17:43:49 +00:00
ctx := helpers.LifecycleCtx(mctx, lc)
lc.Append(fx.Hook{
2021-02-02 17:43:49 +00:00
OnStart: func(context.Context) error {
2021-04-05 11:23:46 +00:00
pcs := newPaymentChannelSettler(ctx, &papi)
2021-08-04 00:10:30 +00:00
ev, err := events.NewEvents(ctx, &papi)
if err != nil {
return err
}
return ev.Called(ctx, pcs.check, pcs.messageHandler, pcs.revertHandler, int(build.MessageConfidence+1), events.NoTimeout, pcs.matcher)
},
})
return nil
}
func newPaymentChannelSettler(ctx context.Context, api settlerAPI) *paymentChannelSettler {
return &paymentChannelSettler{
ctx: ctx,
api: api,
}
}
2021-08-04 00:10:30 +00:00
func (pcs *paymentChannelSettler) check(ctx context.Context, ts *types.TipSet) (done bool, more bool, err error) {
return false, true, nil
}
func (pcs *paymentChannelSettler) messageHandler(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error) {
// Ignore unsuccessful settle messages
if rec.ExitCode != 0 {
return true, nil
}
2020-08-18 15:27:00 +00:00
bestByLane, err := paychmgr.BestSpendableByLane(pcs.ctx, pcs.api, msg.To)
if err != nil {
return true, err
}
var wg sync.WaitGroup
wg.Add(len(bestByLane))
for _, voucher := range bestByLane {
submitMessageCID, err := pcs.api.PaychVoucherSubmit(pcs.ctx, msg.To, voucher, nil, nil)
if err != nil {
return true, err
}
2022-04-20 21:34:28 +00:00
go func(voucher *paychtypes.SignedVoucher, submitMessageCID cid.Cid) {
defer wg.Done()
2021-04-05 11:23:46 +00:00
msgLookup, err := pcs.api.StateWaitMsg(pcs.ctx, submitMessageCID, build.MessageConfidence, api.LookbackNoLimit, true)
if err != nil {
log.Errorf("submitting voucher: %s", err.Error())
2021-05-21 15:39:43 +00:00
return
}
if msgLookup.Receipt.ExitCode != 0 {
log.Errorf("failed submitting voucher: %+v", voucher)
}
}(voucher, submitMessageCID)
}
wg.Wait()
return true, nil
}
func (pcs *paymentChannelSettler) revertHandler(ctx context.Context, ts *types.TipSet) error {
return nil
}
func (pcs *paymentChannelSettler) matcher(msg *types.Message) (matched bool, err error) {
// Check if this is a settle payment channel message
2022-04-20 21:34:28 +00:00
if msg.Method != builtin.MethodsPaych.Settle {
return false, nil
}
// Check if this payment channel is of concern to this node (i.e. tracked in payment channel store),
// and its inbound (i.e. we're getting vouchers that we may need to redeem)
trackedAddresses, err := pcs.api.PaychList(pcs.ctx)
if err != nil {
return false, err
}
for _, addr := range trackedAddresses {
if msg.To == addr {
status, err := pcs.api.PaychStatus(pcs.ctx, addr)
if err != nil {
return false, err
}
if status.Direction == api.PCHInbound {
return true, nil
}
}
}
return false, nil
}