WIP: wiring up the payment channel manager to the api

This commit is contained in:
whyrusleeping 2019-08-12 10:09:56 -07:00
parent 7be7d9137e
commit 6d52abcb2e
7 changed files with 238 additions and 39 deletions

View File

@ -101,9 +101,10 @@ type FullNode interface {
PaychList(context.Context) ([]address.Address, error)
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
PaychClose(context.Context, address.Address) error
PaychVoucherCheck(context.Context, *types.SignedVoucher) error
PaychVoucherCheckValid(context.Context, address.Address, *types.SignedVoucher) error
PaychVoucherCheckSpendable(context.Context, address.Address, *types.SignedVoucher, []byte, []byte) (bool, error)
PaychVoucherCreate(context.Context, address.Address, types.BigInt, uint64) (*types.SignedVoucher, error)
PaychVoucherAdd(context.Context, *types.SignedVoucher) error
PaychVoucherAdd(context.Context, address.Address, *types.SignedVoucher) error
PaychVoucherList(context.Context, address.Address) ([]*types.SignedVoucher, error)
}

View File

@ -73,14 +73,16 @@ type FullNodeStruct struct {
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
PaychCreate func(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) `perm:"sign"`
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
PaychStatus func(context.Context, address.Address) (*PaychStatus, error) `perm:"read"`
PaychClose func(context.Context, address.Address) error `perm:"sign"`
PaychVoucherCheck func(context.Context, *types.SignedVoucher) error `perm:"read"`
PaychVoucherAdd func(context.Context, *types.SignedVoucher) error `perm:"write"`
PaychVoucherCreate func(context.Context, address.Address, types.BigInt, uint64) (*types.SignedVoucher, error) `perm:"sign"`
PaychVoucherList func(context.Context, address.Address) ([]*types.SignedVoucher, error) `perm:"write"`
PaychCreate func(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) `perm:"sign"`
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
PaychStatus func(context.Context, address.Address) (*PaychStatus, error) `perm:"read"`
PaychClose func(context.Context, address.Address) error `perm:"sign"`
PaychVoucherCheck func(context.Context, *types.SignedVoucher) error `perm:"read"`
PaychVoucherCheckValid func(context.Context, address.Address, *types.SignedVoucher) error `perm:"read"`
PaychVoucherCheckSpendable func(context.Context, address.Address, *types.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"`
PaychVoucherAdd func(context.Context, address.Address, *types.SignedVoucher) error `perm:"write"`
PaychVoucherCreate func(context.Context, address.Address, types.BigInt, uint64) (*types.SignedVoucher, error) `perm:"sign"`
PaychVoucherList func(context.Context, address.Address) ([]*types.SignedVoucher, error) `perm:"write"`
}
}
@ -260,12 +262,16 @@ func (c *FullNodeStruct) PaychStatus(ctx context.Context, pch address.Address) (
return c.Internal.PaychStatus(ctx, pch)
}
func (c *FullNodeStruct) PaychVoucherCheck(ctx context.Context, sv *types.SignedVoucher) error {
return c.Internal.PaychVoucherCheck(ctx, sv)
func (c *FullNodeStruct) PaychVoucherCheckValid(ctx context.Context, addr address.Address, sv *types.SignedVoucher) error {
return c.Internal.PaychVoucherCheckValid(ctx, addr, sv)
}
func (c *FullNodeStruct) PaychVoucherAdd(ctx context.Context, sv *types.SignedVoucher) error {
return c.Internal.PaychVoucherAdd(ctx, sv)
func (c *FullNodeStruct) PaychVoucherCheckSpendable(ctx context.Context, addr address.Address, sv *types.SignedVoucher, secret []byte, proof []byte) (bool, error) {
return c.Internal.PaychVoucherCheckSpendable(ctx, addr, sv, secret, proof)
}
func (c *FullNodeStruct) PaychVoucherAdd(ctx context.Context, addr address.Address, sv *types.SignedVoucher) error {
return c.Internal.PaychVoucherAdd(ctx, addr, sv)
}
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {

View File

@ -33,6 +33,7 @@ import (
"github.com/filecoin-project/go-lotus/node/modules/lp2p"
"github.com/filecoin-project/go-lotus/node/modules/testing"
"github.com/filecoin-project/go-lotus/node/repo"
"github.com/filecoin-project/go-lotus/paych"
"github.com/filecoin-project/go-lotus/storage"
)
@ -214,6 +215,9 @@ func Online() Option {
Override(new(*deals.Client), deals.NewClient),
Override(RunDealClientKey, modules.RunDealClient),
Override(new(*paych.Store), modules.PaychStore),
Override(new(*paych.Manager), modules.PaymentChannelManager),
),
// Storage miner

View File

@ -19,6 +19,7 @@ import (
"github.com/filecoin-project/go-lotus/chain/wallet"
"github.com/filecoin-project/go-lotus/miner"
"github.com/filecoin-project/go-lotus/node/client"
"github.com/filecoin-project/go-lotus/paych"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
@ -41,6 +42,7 @@ type FullNodeAPI struct {
PubSub *pubsub.PubSub
Mpool *chain.MessagePool
Wallet *wallet.Wallet
PaychMgr *paych.Manager
}
func (a *FullNodeAPI) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) {
@ -516,7 +518,7 @@ func (a *FullNodeAPI) PaychCreate(ctx context.Context, from, to address.Address,
}
func (a *FullNodeAPI) PaychList(ctx context.Context) ([]address.Address, error) {
panic("nyi")
return a.PaychMgr.ListChannels()
}
func (a *FullNodeAPI) PaychStatus(ctx context.Context, pch address.Address) (*api.PaychStatus, error) {
@ -524,15 +526,60 @@ func (a *FullNodeAPI) PaychStatus(ctx context.Context, pch address.Address) (*ap
}
func (a *FullNodeAPI) PaychClose(ctx context.Context, addr address.Address) error {
panic("nyi")
ci, err := a.PaychMgr.GetChannelInfo(addr)
if err != nil {
return err
}
nonce, err := a.MpoolGetNonce(ctx, ci.ControlAddr)
if err != nil {
return err
}
msg := &types.Message{
To: addr,
From: ci.ControlAddr,
Value: types.NewInt(0),
Method: actors.PCAMethods.Close,
Nonce: nonce,
GasLimit: types.NewInt(500),
GasPrice: types.NewInt(0),
}
b, err := msg.Serialize()
if err != nil {
return err
}
sig, err := a.WalletSign(ctx, ci.ControlAddr, b)
if err != nil {
return err
}
smsg := &types.SignedMessage{
Message: *msg,
Signature: *sig,
}
// TODO: should this block and wait?
return a.MpoolPush(ctx, smsg)
}
func (a *FullNodeAPI) PaychVoucherCheck(ctx context.Context, sv *types.SignedVoucher) error {
panic("nyi")
func (a *FullNodeAPI) PaychVoucherCheckValid(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
return a.PaychMgr.CheckVoucherValid(ctx, ch, sv)
}
func (a *FullNodeAPI) PaychVoucherAdd(ctx context.Context, sv *types.SignedVoucher) error {
panic("nyi")
func (a *FullNodeAPI) 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)
}
func (a *FullNodeAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
if err := a.PaychVoucherCheckValid(ctx, ch, sv); err != nil {
return err
}
return a.PaychMgr.AddVoucher(ctx, ch, sv)
}
func (a *FullNodeAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {

18
node/modules/paych.go Normal file
View File

@ -0,0 +1,18 @@
package modules
import (
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/node/modules/dtypes"
"github.com/filecoin-project/go-lotus/paych"
)
func PaychStore(ds dtypes.MetadataDS) *paych.Store {
return paych.NewStore(ds)
}
func PaymentChannelManager(chain *store.ChainStore, store *paych.Store) (*paych.Manager, error) {
var api api.FullNode
panic("i need a full node api. what do i do")
return paych.NewManager(api, chain, store), nil
}

View File

@ -17,26 +17,56 @@ type paychMgrApi interface {
ChainCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error)
}
type PaychManager struct {
type Manager struct {
chain *store.ChainStore
api paychMgrApi
store *PaychStore
store *Store
}
func NewManager(api paychMgrApi, chain *store.ChainStore, pchstore *PaychStore) *PaychManager {
return &PaychManager{
func NewManager(api paychMgrApi, chain *store.ChainStore, pchstore *Store) *Manager {
return &Manager{
api: api,
chain: chain,
store: pchstore,
}
}
func (pm *PaychManager) TrackChannel(ch address.Address) error {
return pm.store.TrackChannel(ch)
func (pm *Manager) TrackInboundChannel(ctx context.Context, ch address.Address) error {
_, st, err := pm.loadPaychState(ctx, ch)
if err != nil {
return err
}
return pm.store.TrackChannel(&ChannelInfo{
Channel: ch,
Direction: DirInbound,
ControlAddr: st.To,
})
}
func (pm *Manager) TrackOutboundChannel(ctx context.Context, ch address.Address) error {
_, st, err := pm.loadPaychState(ctx, ch)
if err != nil {
return err
}
return pm.store.TrackChannel(&ChannelInfo{
Channel: ch,
Direction: DirOutbound,
ControlAddr: st.From,
})
}
func (pm *Manager) ListChannels() ([]address.Address, error) {
return pm.store.ListChannels()
}
func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) {
return pm.store.getChannelInfo(addr)
}
// checks if the given voucher is valid (is or could become spendable at some point)
func (pm *PaychManager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
act, pca, err := pm.loadPaychState(ctx, ch)
if err != nil {
return err
@ -83,7 +113,7 @@ func (pm *PaychManager) CheckVoucherValid(ctx context.Context, ch address.Addres
}
// checks if the given voucher is currently spendable
func (pm *PaychManager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *types.SignedVoucher, secret []byte, proof []byte) (bool, error) {
func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *types.SignedVoucher, secret []byte, proof []byte) (bool, error) {
owner, err := pm.getPaychOwner(ctx, ch)
if err != nil {
return false, err
@ -115,7 +145,7 @@ func (pm *PaychManager) CheckVoucherSpendable(ctx context.Context, ch address.Ad
return true, nil
}
func (pm *PaychManager) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *actors.PaymentChannelActorState, error) {
func (pm *Manager) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *actors.PaymentChannelActorState, error) {
st, err := pm.chain.TipSetState(pm.chain.GetHeaviestTipSet().Cids())
if err != nil {
return nil, nil, err
@ -140,7 +170,7 @@ func (pm *PaychManager) loadPaychState(ctx context.Context, ch address.Address)
return act, &pcast, nil
}
func (pm *PaychManager) getPaychOwner(ctx context.Context, ch address.Address) (address.Address, error) {
func (pm *Manager) getPaychOwner(ctx context.Context, ch address.Address) (address.Address, error) {
ret, err := pm.api.ChainCall(ctx, &types.Message{
From: ch,
To: ch,
@ -156,3 +186,11 @@ func (pm *PaychManager) getPaychOwner(ctx context.Context, ch address.Address) (
return address.NewFromBytes(ret.Return)
}
func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
if err := pm.CheckVoucherValid(ctx, ch, sv); err != nil {
return err
}
return pm.store.AddVoucher(ch, sv)
}

View File

@ -1,29 +1,114 @@
package paych
import (
"fmt"
"strings"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/ipfs/go-datastore"
dsq "github.com/ipfs/go-datastore/query"
cbor "github.com/ipfs/go-ipld-cbor"
)
type PaychStore struct {
func init() {
cbor.RegisterCborType(ChannelInfo{})
}
type Store struct {
ds datastore.Batching
}
func NewPaychStore(ds datastore.Batching) *PaychStore {
return &PaychStore{
func NewStore(ds datastore.Batching) *Store {
return &Store{
ds: ds,
}
}
func (ps *PaychStore) TrackChannel(ch address.Address) error {
const (
DirInbound = 1
DirOutbound = 2
)
type ChannelInfo struct {
Channel address.Address
ControlAddr address.Address
Direction int
Vouchers []*types.SignedVoucher
}
func dskeyForChannel(addr address.Address) datastore.Key {
return datastore.NewKey("/paych/" + addr.String())
}
func (ps *Store) putChannelInfo(ci *ChannelInfo) error {
k := dskeyForChannel(ci.Channel)
b, err := cbor.DumpObject(ci)
if err != nil {
return err
}
return ps.ds.Put(k, b)
}
func (ps *Store) getChannelInfo(addr address.Address) (*ChannelInfo, error) {
k := dskeyForChannel(addr)
b, err := ps.ds.Get(k)
if err != nil {
return nil, err
}
var ci ChannelInfo
if err := cbor.DecodeInto(b, &ci); err != nil {
return nil, err
}
return &ci, nil
}
func (ps *Store) TrackChannel(ch *ChannelInfo) error {
_, err := ps.getChannelInfo(ch.Channel)
switch err {
default:
return err
case nil:
return fmt.Errorf("already tracking channel: %s", ch.Channel)
case datastore.ErrNotFound:
return ps.putChannelInfo(ch)
}
}
func (ps *Store) ListChannels() ([]address.Address, error) {
res, err := ps.ds.Query(dsq.Query{Prefix: "/paych/", KeysOnly: true})
if err != nil {
return nil, err
}
var out []address.Address
for {
res, ok := res.NextSync()
if !ok {
break
}
addr, err := address.NewFromString(strings.TrimPrefix(res.Key, "/paych/"))
if err != nil {
return nil, err
}
out = append(out, addr)
}
return out, nil
}
func (ps *Store) AddVoucher(ch address.Address, sv *types.SignedVoucher) error {
panic("nyi")
}
func (ps *PaychStore) AddVoucher(sv *types.SignedVoucher) error {
panic("nyi")
}
func (ps *PaychStore) VouchersForPaych(addr address.Address) ([]*types.SignedVoucher, error) {
func (ps *Store) VouchersForPaych(addr address.Address) ([]*types.SignedVoucher, error) {
panic("nyi")
}