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
|
PaychVoucherCheckValid(context.Context, address.Address, *types.SignedVoucher) error
|
||||||
PaychVoucherCheckSpendable(context.Context, address.Address, *types.SignedVoucher, []byte, []byte) (bool, error)
|
PaychVoucherCheckSpendable(context.Context, address.Address, *types.SignedVoucher, []byte, []byte) (bool, error)
|
||||||
PaychVoucherCreate(context.Context, address.Address, types.BigInt, uint64) (*types.SignedVoucher, 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)
|
PaychVoucherList(context.Context, address.Address) ([]*types.SignedVoucher, error)
|
||||||
PaychVoucherSubmit(context.Context, address.Address, *types.SignedVoucher) (cid.Cid, 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"`
|
PaychVoucherCheck func(context.Context, *types.SignedVoucher) error `perm:"read"`
|
||||||
PaychVoucherCheckValid func(context.Context, address.Address, *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"`
|
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"`
|
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"`
|
PaychVoucherList func(context.Context, address.Address) ([]*types.SignedVoucher, error) `perm:"write"`
|
||||||
PaychVoucherSubmit func(context.Context, address.Address, *types.SignedVoucher) (cid.Cid, error) `perm:"sign"`
|
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)
|
return c.Internal.PaychVoucherCheckSpendable(ctx, addr, sv, secret, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FullNodeStruct) PaychVoucherAdd(ctx context.Context, addr address.Address, sv *types.SignedVoucher) error {
|
func (c *FullNodeStruct) PaychVoucherAdd(ctx context.Context, addr address.Address, sv *types.SignedVoucher, proof []byte) error {
|
||||||
return c.Internal.PaychVoucherAdd(ctx, addr, sv)
|
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) {
|
func (c *FullNodeStruct) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*types.SignedVoucher, error) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
@ -42,6 +43,24 @@ func (sv *SignedVoucher) EncodedString() (string, error) {
|
|||||||
return base64.RawURLEncoding.EncodeToString(data), nil
|
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) {
|
func DecodeSignedVoucher(s string) (*SignedVoucher, error) {
|
||||||
data, err := base64.RawURLEncoding.DecodeString(s)
|
data, err := base64.RawURLEncoding.DecodeString(s)
|
||||||
if err != nil {
|
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)
|
return a.PaychMgr.CheckVoucherSpendable(ctx, ch, sv, secret, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *types.SignedVoucher) error {
|
func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *types.SignedVoucher, proof []byte) error {
|
||||||
_ = a.PaychMgr.TrackInboundChannel(ctx, ch)
|
_ = a.PaychMgr.TrackInboundChannel(ctx, ch) // TODO: expose those calls
|
||||||
|
|
||||||
if err := a.PaychVoucherCheckValid(ctx, ch, sv); err != nil {
|
if err := a.PaychVoucherCheckValid(ctx, ch, sv); err != nil {
|
||||||
return err
|
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
|
// 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
|
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)
|
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) {
|
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) {
|
func (a *PaychAPI) PaychVoucherSubmit(ctx context.Context, ch address.Address, sv *types.SignedVoucher) (cid.Cid, error) {
|
||||||
|
@ -4,16 +4,19 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"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/actors"
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"github.com/filecoin-project/go-lotus/chain/state"
|
"github.com/filecoin-project/go-lotus/chain/state"
|
||||||
"github.com/filecoin-project/go-lotus/chain/store"
|
"github.com/filecoin-project/go-lotus/chain/store"
|
||||||
"github.com/filecoin-project/go-lotus/chain/types"
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
"github.com/filecoin-project/go-lotus/chain/vm"
|
"github.com/filecoin-project/go-lotus/chain/vm"
|
||||||
|
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("paych")
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
chain *store.ChainStore
|
chain *store.ChainStore
|
||||||
store *Store
|
store *Store
|
||||||
@ -118,6 +121,24 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address
|
|||||||
return false, err
|
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{
|
enc, err := actors.SerializeParams(&actors.PCAUpdateChannelStateParams{
|
||||||
Sv: *sv,
|
Sv: *sv,
|
||||||
Secret: secret,
|
Secret: secret,
|
||||||
@ -186,15 +207,15 @@ func (pm *Manager) getPaychOwner(ctx context.Context, ch address.Address) (addre
|
|||||||
return address.NewFromBytes(ret.Return)
|
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 {
|
if err := pm.CheckVoucherValid(ctx, ch, sv); err != nil {
|
||||||
return err
|
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
|
// TODO: just having a passthrough method like this feels odd. Seems like
|
||||||
// there should be some filtering we're doing here
|
// there should be some filtering we're doing here
|
||||||
return pm.store.VouchersForPaych(ch)
|
return pm.store.VouchersForPaych(ch)
|
||||||
@ -208,9 +229,9 @@ func (pm *Manager) NextNonceForLane(ctx context.Context, ch address.Address, lan
|
|||||||
|
|
||||||
var maxnonce uint64
|
var maxnonce uint64
|
||||||
for _, v := range vouchers {
|
for _, v := range vouchers {
|
||||||
if v.Lane == lane {
|
if v.Voucher.Lane == lane {
|
||||||
if v.Nonce > maxnonce {
|
if v.Voucher.Nonce > maxnonce {
|
||||||
maxnonce = v.Nonce
|
maxnonce = v.Voucher.Nonce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package paych
|
package paych
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@ -18,6 +19,7 @@ import (
|
|||||||
var ErrChannelNotTracked = errors.New("channel not tracked")
|
var ErrChannelNotTracked = errors.New("channel not tracked")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
cbor.RegisterCborType(VoucherInfo{})
|
||||||
cbor.RegisterCborType(ChannelInfo{})
|
cbor.RegisterCborType(ChannelInfo{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,11 +39,16 @@ const (
|
|||||||
DirOutbound = 2
|
DirOutbound = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type VoucherInfo struct {
|
||||||
|
Voucher *types.SignedVoucher
|
||||||
|
Proof []byte
|
||||||
|
}
|
||||||
|
|
||||||
type ChannelInfo struct {
|
type ChannelInfo struct {
|
||||||
Channel address.Address
|
Channel address.Address
|
||||||
ControlAddr address.Address
|
ControlAddr address.Address
|
||||||
Direction int
|
Direction int
|
||||||
Vouchers []*types.SignedVoucher
|
Vouchers []*VoucherInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func dskeyForChannel(addr address.Address) datastore.Key {
|
func dskeyForChannel(addr address.Address) datastore.Key {
|
||||||
@ -118,18 +125,53 @@ func (ps *Store) ListChannels() ([]address.Address, error) {
|
|||||||
return out, nil
|
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)
|
ci, err := ps.getChannelInfo(ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
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)
|
ci, err := ps.getChannelInfo(ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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