Skip to content

Commit

Permalink
tapgarden+multi: custodian initialises proof courier using output addr
Browse files Browse the repository at this point in the history
  • Loading branch information
ffranr committed Aug 26, 2023
1 parent ee66887 commit cb7d1e0
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 80 deletions.
166 changes: 109 additions & 57 deletions proof/courier.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,6 @@ const (
ApertureCourier = "hashmail"
)

// NewCourierType returns the CourierType that corresponds to the given string.
func NewCourierType(scheme string) (CourierType, error) {
switch scheme {
case ApertureCourier:
return ApertureCourier, nil
}

return DisabledCourier, fmt.Errorf("unknown courier address "+
"protocol: %v", scheme)
}

func ParseCourierAddr(addr string) (*url.URL, error) {
// Parse URI.
urlAddr, err := url.ParseRequestURI(addr)
if err != nil {
return nil, fmt.Errorf("invalid proof courier URI address: %w",
err)
}

// Validate port number.
if urlAddr.Port() == "" {
return nil, fmt.Errorf("proof courier URI address port "+
"unspecified: %w", err)
}

// Validate protocol supported.
_, err = NewCourierType(urlAddr.Scheme)
if err != nil {
return nil, fmt.Errorf("invalid proof courier protocol: %w",
err)
}

return urlAddr, nil
}

// CourierHarness interface is an integration testing harness for a proof
// courier service.
type CourierHarness interface {
Expand All @@ -90,20 +55,123 @@ type CourierHarness interface {
// receiver can use this to fetch a proof from the sender.
//
// TODO(roasbeef): FileSystemCourier, RpcCourier
type Courier[Addr any] interface {
type Courier interface {
// DeliverProof attempts to delivery a proof to the receiver, using the
// information in the Addr type.
DeliverProof(context.Context, Addr, *AnnotatedProof) error
DeliverProof(context.Context, Recipient, *AnnotatedProof) error

// ReceiveProof attempts to obtain a proof as identified by the passed
// locator from the source encapsulated within the specified address.
ReceiveProof(context.Context, Addr, Locator) (*AnnotatedProof, error)
ReceiveProof(context.Context, Recipient, Locator) (*AnnotatedProof,
error)

// SetSubscribers sets the set of subscribers that will be notified
// of proof courier related events.
SetSubscribers(map[uint64]*fn.EventReceiver[fn.Event])
}

// CourierAddr is a fully validated courier address (including protocol specific
// validation).
type CourierAddr interface {
// Url returns the url.URL representation of the courier address.
Url() *url.URL

// NewCourier generates a new courier service handle.
NewCourier(ctx context.Context, cfg *CourierCfg) (Courier, error)
}

// ParseCourierAddrString parses a proof courier address string and returns a
// protocol specific courier address instance.
func ParseCourierAddrString(addr string) (CourierAddr, error) {
// Parse URI.
urlAddr, err := url.ParseRequestURI(addr)
if err != nil {
return nil, fmt.Errorf("invalid proof courier URI address: %w",
err)
}

return ParseCourierAddrUrl(*urlAddr)
}

// ParseCourierAddrUrl parses a proof courier address url.URL and returns a
// protocol specific courier address instance.
func ParseCourierAddrUrl(addr url.URL) (CourierAddr, error) {
// Create new courier addr based on URL scheme.
switch addr.Scheme {
case ApertureCourier:
return NewHashMailCourierAddr(addr)
}

return nil, fmt.Errorf("unknown courier address protocol: %v",
addr.Scheme)
}

// HashMailCourierAddr is a hashmail protocol specific implementation of the
// CourierAddr interface.
type HashMailCourierAddr struct {
addr url.URL
}

// Url returns the url.URL representation of the hashmail courier address.
func (h *HashMailCourierAddr) Url() *url.URL {
return &h.addr
}

// NewCourier generates a new courier service handle.
func (h *HashMailCourierAddr) NewCourier(_ context.Context,
cfg *CourierCfg) (Courier, error) {

hashMailBox, err := NewHashMailBox(&h.addr, cfg.HashMailCfg.TlsCertPath)
if err != nil {
return nil, fmt.Errorf("unable to make mailbox: %v",
err)
}

subscribers := make(
map[uint64]*fn.EventReceiver[fn.Event],
)
return &HashMailCourier{
cfg: cfg.HashMailCfg,
mailbox: hashMailBox,
deliveryLog: cfg.DeliveryLog,
subscribers: subscribers,
}, nil
}

// NewHashMailCourierAddr generates a new hashmail courier address from a given
// URL. This function also performs hashmail protocol specific address
// validation.
func NewHashMailCourierAddr(addr url.URL) (*HashMailCourierAddr, error) {
// We expect the port number to be specified for a hashmail service.
if addr.Port() == "" {
return nil, fmt.Errorf("hashmail proof courier URI address " +
"port unspecified")
}

return &HashMailCourierAddr{
addr,
}, nil
}

// NewCourier instantiates a new courier service handle given a service URL
// address.
func NewCourier(ctx context.Context, addr url.URL, cfg *CourierCfg) (Courier,
error) {

courierAddr, err := ParseCourierAddrUrl(addr)
if err != nil {
return nil, err
}

return courierAddr.NewCourier(ctx, cfg)
}

type CourierCfg struct {
HashMailCfg *HashMailCourierCfg

DeliveryLog DeliveryLog
}

// ProofMailbox represents an abstract store-and-forward mailbox that can be
// used to send/receive proofs.
type ProofMailbox interface {
Expand Down Expand Up @@ -403,7 +471,8 @@ type BackoffCfg struct {
MaxBackoff time.Duration `long:"maxbackoff" description:"The maximum backoff time to wait before retrying to deliver the proof to the receiver."`
}

// HashMailCourier is an implementation of the Courier interfaces that
// HashMailCourier is a hashmail proof courier service handle. It implements the
// Courier interface.
type HashMailCourier struct {
// cfg contains the courier's configuration parameters.
cfg *HashMailCourierCfg
Expand All @@ -423,23 +492,6 @@ type HashMailCourier struct {
subscriberMtx sync.Mutex
}

// NewHashMailCourier implements the Courier interface using the specified
// ProofMailbox. This instance of the Courier relies on the Taproot Asset
// address itself as the parametrized address type.
func NewHashMailCourier(cfg *HashMailCourierCfg, mailbox ProofMailbox,
deliveryLog DeliveryLog) (*HashMailCourier, error) {

subscribers := make(
map[uint64]*fn.EventReceiver[fn.Event],
)
return &HashMailCourier{
cfg: cfg,
mailbox: mailbox,
deliveryLog: deliveryLog,
subscribers: subscribers,
}, nil
}

// DeliverProof attempts to delivery a proof to the receiver, using the
// information in the Addr type.
//
Expand Down Expand Up @@ -790,7 +842,7 @@ func (h *HashMailCourier) SetSubscribers(

// A compile-time assertion to ensure the HashMailCourier meets the
// proof.Courier interface.
var _ Courier[Recipient] = (*HashMailCourier)(nil)
var _ Courier = (*HashMailCourier)(nil)

// DeliveryLog is an interface that allows the courier to log the (attempted)
// delivery of a proof.
Expand Down
8 changes: 7 additions & 1 deletion rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -991,13 +991,19 @@ func (r *rpcServer) NewAddr(ctx context.Context,
// the default specified in the config.
courierAddr := r.cfg.DefaultProofCourierAddr
if in.ProofCourierAddr != "" {
courierAddr, err = proof.ParseCourierAddr(
addr, err := proof.ParseCourierAddrString(
in.ProofCourierAddr,
)
if err != nil {
return nil, fmt.Errorf("invalid proof courier "+
"address: %w", err)
}

// At this point, we do not intend on creating a proof courier
// service instance. We are only interested in parsing and
// validating the address. We therefore convert the address into
// an url.URL type for storage in the address book.
courierAddr = addr.Url()
}

// Check that the proof courier address is set. This should never
Expand Down
35 changes: 20 additions & 15 deletions tapcfg/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
fallbackHashmailCourierAddr := fmt.Sprintf(
"%s://%s", proof.ApertureCourier, fallbackHashMailAddr,
)
proofCourierAddr, err := proof.ParseCourierAddr(
proofCourierAddr, err := proof.ParseCourierAddrString(
fallbackHashmailCourierAddr,
)
if err != nil {
Expand All @@ -171,7 +171,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,

// If default proof courier address is set, use it as the default.
if cfg.DefaultProofCourierAddr != "" {
proofCourierAddr, err = proof.ParseCourierAddr(
proofCourierAddr, err = proof.ParseCourierAddrString(
cfg.DefaultProofCourierAddr,
)
if err != nil {
Expand All @@ -180,12 +180,12 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
}
}

var hashMailCourier proof.Courier[proof.Recipient]
var hashMailCourier proof.Courier
if cfg.HashMailCourier != nil &&
proofCourierAddr.Scheme == proof.ApertureCourier {
proofCourierAddr.Type() == proof.ApertureCourier {

hashMailBox, err := proof.NewHashMailBox(
proofCourierAddr, cfg.HashMailCourier.TlsCertPath,
proofCourierAddr.Url(), cfg.HashMailCourier.TlsCertPath,
)
if err != nil {
return nil, fmt.Errorf("unable to make mailbox: %v",
Expand All @@ -201,6 +201,11 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
}
}

proofCourierCfg := proof.CourierCfg{
HashMailCfg: cfg.HashMailCourier,
DeliveryLog: assetStore,
}

reOrgWatcher := tapgarden.NewReOrgWatcher(&tapgarden.ReOrgWatcherConfig{
ChainBridge: chainBridge,
ProofArchive: proofArchive,
Expand Down Expand Up @@ -303,20 +308,20 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
}),
AssetCustodian: tapgarden.NewCustodian(
&tapgarden.CustodianConfig{
ChainParams: &tapChainParams,
WalletAnchor: walletAnchor,
ChainBridge: chainBridge,
AddrBook: addrBook,
ProofArchive: proofArchive,
ProofNotifier: assetStore,
ErrChan: mainErrChan,
ProofCourier: hashMailCourier,
ProofWatcher: reOrgWatcher,
ChainParams: &tapChainParams,
WalletAnchor: walletAnchor,
ChainBridge: chainBridge,
AddrBook: addrBook,
ProofArchive: proofArchive,
ProofNotifier: assetStore,
ErrChan: mainErrChan,
ProofCourierCfg: &proofCourierCfg,
ProofWatcher: reOrgWatcher,
},
),
ChainBridge: chainBridge,
AddrBook: addrBook,
DefaultProofCourierAddr: proofCourierAddr,
DefaultProofCourierAddr: proofCourierAddr.Url(),
ProofArchive: proofArchive,
AssetWallet: assetWallet,
CoinSelect: coinSelect,
Expand Down
2 changes: 1 addition & 1 deletion tapfreighter/chain_porter.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type ChainPorterConfig struct {

// ProofCourier is used to optionally deliver the final proof to the
// user using an asynchronous transport mechanism.
ProofCourier proof.Courier[proof.Recipient]
ProofCourier proof.Courier

// ProofWatcher is used to watch new proofs for their anchor transaction
// to be confirmed safely with a minimum number of confirmations.
Expand Down
32 changes: 26 additions & 6 deletions tapgarden/custodian.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ type CustodianConfig struct {
// being available in the relational database).
ProofNotifier proof.NotifyArchiver

// ProofCourier is used to optionally deliver the final proof to the
// user using an asynchronous transport mechanism.
ProofCourier proof.Courier[proof.Recipient]
// ProofCourierCfg is a general config applicable to all proof courier
// service handles.
ProofCourierCfg *proof.CourierCfg

// ProofWatcher is used to watch new proofs for their anchor transaction
// to be confirmed safely with a minimum number of confirmations.
Expand Down Expand Up @@ -337,7 +337,13 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error {
return err
}

if c.cfg.ProofCourier == nil || addr == nil {
// TODO(ffranr): This proof courier disabled check should be
// removed. It was implemented because some integration test do
// not setup and use a proof courier.
proofCourierDisabled := c.cfg.ProofCourierCfg == nil ||
c.cfg.ProofCourierCfg.HashMailCfg == nil ||
addr == nil
if proofCourierDisabled {
continue
}

Expand All @@ -351,16 +357,30 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error {
ctx, cancel := c.WithCtxQuitNoTimeout()
defer cancel()

assetID := addr.AssetID

log.Debugf("Waiting to receive proof for script key %x",
addr.ScriptKey.SerializeCompressed())

assetID := addr.AssetID
// Initiate proof courier service handle from the proof
// courier address found in the Tap address.
courier, err := proof.NewCourier(
ctx, addr.ProofCourierAddr,
c.cfg.ProofCourierCfg,
)
if err != nil {
log.Errorf("unable to initiate proof courier "+
"service handle: %v", err)
return
}

// Attempt to receive proof via proof courier service.
recipient := proof.Recipient{
ScriptKey: &addr.ScriptKey,
AssetID: assetID,
Amount: addr.Amount,
}
addrProof, err := c.cfg.ProofCourier.ReceiveProof(
addrProof, err := courier.ReceiveProof(
ctx, recipient, proof.Locator{
AssetID: &assetID,
ScriptKey: addr.ScriptKey,
Expand Down

0 comments on commit cb7d1e0

Please sign in to comment.