paychmgr: store proofs with vouchers
This commit is contained in:
parent
8b29c98919
commit
5200a37349
@ -114,7 +114,7 @@ type FullNode interface {
|
||||
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, address.Address, *types.SignedVoucher) error
|
||||
PaychVoucherAdd(context.Context, address.Address, *types.SignedVoucher, []byte) error
|
||||
PaychVoucherList(context.Context, address.Address) ([]*types.SignedVoucher, error)
|
||||
PaychVoucherSubmit(context.Context, address.Address, *types.SignedVoucher) (cid.Cid, error)
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ type FullNodeStruct struct {
|
||||
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"`
|
||||
PaychVoucherAdd func(context.Context, address.Address, *types.SignedVoucher, []byte) 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"`
|
||||
PaychVoucherSubmit func(context.Context, address.Address, *types.SignedVoucher) (cid.Cid, error) `perm:"sign"`
|
||||
@ -303,8 +303,8 @@ func (c *FullNodeStruct) PaychVoucherCheckSpendable(ctx context.Context, addr ad
|
||||
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) PaychVoucherAdd(ctx context.Context, addr address.Address, sv *types.SignedVoucher, proof []byte) error {
|
||||
return c.Internal.PaychVoucherAdd(ctx, addr, sv, proof)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
@ -42,6 +43,24 @@ func (sv *SignedVoucher) EncodedString() (string, error) {
|
||||
return base64.RawURLEncoding.EncodeToString(data), nil
|
||||
}
|
||||
|
||||
func (sv *SignedVoucher) Equals(other *SignedVoucher) bool {
|
||||
// TODO: make this less bad
|
||||
|
||||
selfB, err := cbor.DumpObject(sv)
|
||||
if err != nil {
|
||||
log.Errorf("SignedVoucher.Equals: dump self: %s", err)
|
||||
return false
|
||||
}
|
||||
|
||||
otherB, err := cbor.DumpObject(other)
|
||||
if err != nil {
|
||||
log.Errorf("SignedVoucher.Equals: dump other: %s", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return bytes.Equal(selfB, otherB)
|
||||
}
|
||||
|
||||
func DecodeSignedVoucher(s string) (*SignedVoucher, error) {
|
||||
data, err := base64.RawURLEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
|
@ -154,14 +154,14 @@ func (a *PaychAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Ad
|
||||
return a.PaychMgr.CheckVoucherSpendable(ctx, ch, sv, secret, proof)
|
||||
}
|
||||
|
||||
func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
|
||||
_ = a.PaychMgr.TrackInboundChannel(ctx, ch)
|
||||
func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *types.SignedVoucher, proof []byte) error {
|
||||
_ = a.PaychMgr.TrackInboundChannel(ctx, ch) // TODO: expose those calls
|
||||
|
||||
if err := a.PaychVoucherCheckValid(ctx, ch, sv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return a.PaychMgr.AddVoucher(ctx, ch, sv)
|
||||
return a.PaychMgr.AddVoucher(ctx, ch, sv, proof)
|
||||
}
|
||||
|
||||
// PaychVoucherCreate creates a new signed voucher on the given payment channel
|
||||
@ -199,7 +199,7 @@ func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address,
|
||||
|
||||
sv.Signature = sig
|
||||
|
||||
if err := a.PaychMgr.AddVoucher(ctx, pch, sv); err != nil {
|
||||
if err := a.PaychMgr.AddVoucher(ctx, pch, sv, nil); err != nil {
|
||||
return nil, xerrors.Errorf("failed to persist voucher: %w", err)
|
||||
}
|
||||
|
||||
@ -207,7 +207,17 @@ func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address,
|
||||
}
|
||||
|
||||
func (a *PaychAPI) PaychVoucherList(ctx context.Context, pch address.Address) ([]*types.SignedVoucher, error) {
|
||||
return a.PaychMgr.ListVouchers(ctx, pch)
|
||||
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
|
||||
}
|
||||
|
||||
func (a *PaychAPI) PaychVoucherSubmit(ctx context.Context, ch address.Address, sv *types.SignedVoucher) (cid.Cid, error) {
|
||||
|
@ -4,16 +4,19 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/state"
|
||||
"github.com/filecoin-project/go-lotus/chain/store"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/chain/vm"
|
||||
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
)
|
||||
|
||||
var log = logging.Logger("paych")
|
||||
|
||||
type Manager struct {
|
||||
chain *store.ChainStore
|
||||
store *Store
|
||||
@ -118,6 +121,24 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address
|
||||
return false, err
|
||||
}
|
||||
|
||||
if sv.Extra != nil && proof == nil {
|
||||
known, err := pm.ListVouchers(ctx, ch)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, v := range known {
|
||||
if v.Proof != nil && v.Voucher.Equals(sv) {
|
||||
log.Info("CheckVoucherSpendable: using stored proof")
|
||||
proof = v.Proof
|
||||
break
|
||||
}
|
||||
}
|
||||
if proof == nil {
|
||||
log.Warn("CheckVoucherSpendable: nil proof for voucher with validation")
|
||||
}
|
||||
}
|
||||
|
||||
enc, err := actors.SerializeParams(&actors.PCAUpdateChannelStateParams{
|
||||
Sv: *sv,
|
||||
Secret: secret,
|
||||
@ -186,15 +207,15 @@ func (pm *Manager) getPaychOwner(ctx context.Context, ch address.Address) (addre
|
||||
return address.NewFromBytes(ret.Return)
|
||||
}
|
||||
|
||||
func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
|
||||
func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *types.SignedVoucher, proof []byte) error {
|
||||
if err := pm.CheckVoucherValid(ctx, ch, sv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pm.store.AddVoucher(ch, sv)
|
||||
return pm.store.AddVoucher(ch, sv, proof)
|
||||
}
|
||||
|
||||
func (pm *Manager) ListVouchers(ctx context.Context, ch address.Address) ([]*types.SignedVoucher, error) {
|
||||
func (pm *Manager) ListVouchers(ctx context.Context, ch address.Address) ([]*VoucherInfo, error) {
|
||||
// TODO: just having a passthrough method like this feels odd. Seems like
|
||||
// there should be some filtering we're doing here
|
||||
return pm.store.VouchersForPaych(ch)
|
||||
@ -208,9 +229,9 @@ func (pm *Manager) NextNonceForLane(ctx context.Context, ch address.Address, lan
|
||||
|
||||
var maxnonce uint64
|
||||
for _, v := range vouchers {
|
||||
if v.Lane == lane {
|
||||
if v.Nonce > maxnonce {
|
||||
maxnonce = v.Nonce
|
||||
if v.Voucher.Lane == lane {
|
||||
if v.Voucher.Nonce > maxnonce {
|
||||
maxnonce = v.Voucher.Nonce
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
var ErrChannelNotTracked = errors.New("channel not tracked")
|
||||
|
||||
func init() {
|
||||
cbor.RegisterCborType(VoucherInfo{})
|
||||
cbor.RegisterCborType(ChannelInfo{})
|
||||
}
|
||||
|
||||
@ -37,11 +39,16 @@ const (
|
||||
DirOutbound = 2
|
||||
)
|
||||
|
||||
type VoucherInfo struct {
|
||||
Voucher *types.SignedVoucher
|
||||
Proof []byte
|
||||
}
|
||||
|
||||
type ChannelInfo struct {
|
||||
Channel address.Address
|
||||
ControlAddr address.Address
|
||||
Direction int
|
||||
Vouchers []*types.SignedVoucher
|
||||
Vouchers []*VoucherInfo
|
||||
}
|
||||
|
||||
func dskeyForChannel(addr address.Address) datastore.Key {
|
||||
@ -118,18 +125,53 @@ func (ps *Store) ListChannels() ([]address.Address, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (ps *Store) AddVoucher(ch address.Address, sv *types.SignedVoucher) error {
|
||||
func (ps *Store) AddVoucher(ch address.Address, sv *types.SignedVoucher, proof []byte) error {
|
||||
ci, err := ps.getChannelInfo(ch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ci.Vouchers = append(ci.Vouchers, sv)
|
||||
svs, err := sv.EncodedString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// look for duplicates
|
||||
for i, v := range ci.Vouchers {
|
||||
osvs, err := v.Voucher.EncodedString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if osvs != svs {
|
||||
continue
|
||||
}
|
||||
if v.Proof != nil {
|
||||
if !bytes.Equal(v.Proof, proof) {
|
||||
log.Warnf("AddVoucher: multiple proofs for single voucher: v:'%s', storing both", svs)
|
||||
break
|
||||
}
|
||||
log.Warnf("AddVoucher: voucher re-added with matching proof: v:'%s'", svs)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Warnf("AddVoucher: adding proof to stored voucher")
|
||||
ci.Vouchers[i] = &VoucherInfo{
|
||||
Voucher: v.Voucher,
|
||||
Proof: proof,
|
||||
}
|
||||
|
||||
return ps.putChannelInfo(ci)
|
||||
}
|
||||
|
||||
ci.Vouchers = append(ci.Vouchers, &VoucherInfo{
|
||||
Voucher: sv,
|
||||
Proof: proof,
|
||||
})
|
||||
|
||||
return ps.putChannelInfo(ci)
|
||||
}
|
||||
|
||||
func (ps *Store) VouchersForPaych(ch address.Address) ([]*types.SignedVoucher, error) {
|
||||
func (ps *Store) VouchersForPaych(ch address.Address) ([]*VoucherInfo, error) {
|
||||
ci, err := ps.getChannelInfo(ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
29
paych/watcher.go
Normal file
29
paych/watcher.go
Normal file
@ -0,0 +1,29 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/events"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
)
|
||||
|
||||
type watchedLane struct {
|
||||
bestVoucher *types.SignedVoucher
|
||||
closed bool
|
||||
}
|
||||
|
||||
type inboundWatcher struct {
|
||||
ev *events.Events
|
||||
|
||||
paych *address.Address
|
||||
|
||||
control address.Address
|
||||
|
||||
lanes map[uint64]*watchedLane
|
||||
|
||||
closeAt uint64 // at what H do we plan to call close
|
||||
collectAt uint64 // at what H do we plan to call collect
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user