Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(SPV-1020): move paymail servant to separate package and use it in engine #697

Merged
merged 6 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 18 additions & 22 deletions engine/action_contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,37 @@ import (

"github.com/bitcoin-sv/go-paymail"
"github.com/bitcoin-sv/spv-wallet/engine/datastore"
paymailclient "github.com/bitcoin-sv/spv-wallet/engine/paymail"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
)

// UpsertContact adds a new contact if not exists or updates the existing one.
func (c *Client) UpsertContact(ctx context.Context, ctcFName, ctcPaymail, requesterXPubID, requesterPaymail string, opts ...ModelOps) (*Contact, error) {
reqPm, err := c.getPaymail(ctx, requesterXPubID, requesterPaymail)
func (c *Client) UpsertContact(ctx context.Context, ctcFName, ctcPaymail, requesterXPubID, requesterPaymailAddress string, opts ...ModelOps) (*Contact, error) {
requesterPaymail, err := c.getPaymail(ctx, requesterXPubID, requesterPaymailAddress)
if err != nil {
return nil, err
}

pmSrvnt := &PaymailServant{
cs: c.Cachestore(),
pc: c.PaymailClient(),
}
contactPm, err := pmSrvnt.GetSanitizedPaymail(ctcPaymail)
paymailService := c.PaymailService()

contactPaymail, err := paymailService.GetSanitizedPaymail(ctcPaymail)
if err != nil {
return nil, spverrors.Wrapf(err, "requested contact paymail is invalid")
}

contact, err := c.upsertContact(ctx, pmSrvnt, requesterXPubID, ctcFName, contactPm, opts...)
contact, err := c.upsertContact(ctx, paymailService, requesterXPubID, ctcFName, contactPaymail, opts...)
if err != nil {
return nil, err
}

// request new contact
requesterContactRequest := paymail.PikeContactRequestPayload{
FullName: reqPm.PublicName,
Paymail: reqPm.String(),
FullName: requesterPaymail.PublicName,
Paymail: requesterPaymail.String(),
}
if _, err = pmSrvnt.AddContactRequest(ctx, contactPm, &requesterContactRequest); err != nil {
if _, err = paymailService.AddContactRequest(ctx, contactPaymail, &requesterContactRequest); err != nil {
c.Logger().Warn().
Str("requesterPaymail", reqPm.String()).
Str("requesterPaymail", requesterPaymail.String()).
Str("requestedContact", ctcPaymail).
Msgf("adding contact request failed: %s", err.Error())

Expand All @@ -49,25 +48,22 @@ func (c *Client) UpsertContact(ctx context.Context, ctcFName, ctcPaymail, reques

// AddContactRequest adds a new contact invitation if contact not exits or just checking if contact has still the same pub key if contact exists.
func (c *Client) AddContactRequest(ctx context.Context, fullName, paymailAdress, requesterXPubID string, opts ...ModelOps) (*Contact, error) {
pmSrvnt := &PaymailServant{
cs: c.Cachestore(),
pc: c.PaymailClient(),
}
paymailService := c.PaymailService()

contactPm, err := pmSrvnt.GetSanitizedPaymail(paymailAdress)
contactPaymail, err := paymailService.GetSanitizedPaymail(paymailAdress)
if err != nil {
c.Logger().Error().Msgf("requested contact paymail is invalid. Reason: %s", err.Error())
return nil, spverrors.ErrRequestedContactInvalid
}

contactPki, err := pmSrvnt.GetPkiForPaymail(ctx, contactPm)
contactPki, err := paymailService.GetPkiForPaymail(ctx, contactPaymail)
if err != nil {
c.Logger().Error().Msgf("getting PKI for %s failed. Reason: %v", paymailAdress, err)
return nil, spverrors.ErrGettingPKIFailed
}

// check if exists already
contact, err := getContact(ctx, contactPm.Address, requesterXPubID, c.DefaultModelOptions()...)
contact, err := getContact(ctx, contactPaymail.Address, requesterXPubID, c.DefaultModelOptions()...)
if err != nil {
return nil, err
}
Expand All @@ -78,7 +74,7 @@ func (c *Client) AddContactRequest(ctx context.Context, fullName, paymailAdress,
} else {
contact = newContact(
fullName,
contactPm.Address,
contactPaymail.Address,
contactPki.PubKey,
requesterXPubID,
ContactAwaitAccept,
Expand Down Expand Up @@ -372,8 +368,8 @@ func (c *Client) getPaymail(ctx context.Context, xpubID, paymailAddr string) (*P
return paymails[0], nil
}

func (c *Client) upsertContact(ctx context.Context, pmSrvnt *PaymailServant, reqXPubID, ctcFName string, ctcPaymail *paymail.SanitisedPaymail, opts ...ModelOps) (*Contact, error) {
contactPki, err := pmSrvnt.GetPkiForPaymail(ctx, ctcPaymail)
func (c *Client) upsertContact(ctx context.Context, paymailService paymailclient.ServiceClient, reqXPubID, ctcFName string, ctcPaymail *paymail.SanitisedPaymail, opts ...ModelOps) (*Contact, error) {
contactPki, err := paymailService.GetPkiForPaymail(ctx, ctcPaymail)
if err != nil {
return nil, spverrors.ErrGettingPKIFailed
}
Expand Down
10 changes: 6 additions & 4 deletions engine/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/bitcoin-sv/spv-wallet/engine/logging"
"github.com/bitcoin-sv/spv-wallet/engine/metrics"
"github.com/bitcoin-sv/spv-wallet/engine/notifications"
paymailclient "github.com/bitcoin-sv/spv-wallet/engine/paymail"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
"github.com/bitcoin-sv/spv-wallet/engine/taskmanager"
"github.com/mrz1836/go-cachestore"
Expand Down Expand Up @@ -99,8 +100,9 @@ type (

// paymailOptions holds the configuration for Paymail
paymailOptions struct {
client paymail.ClientInterface // Paymail client for communicating with Paymail providers
serverConfig *PaymailServerOptions // Server configuration if Paymail is enabled
client paymail.ClientInterface // Paymail client for communicating with Paymail providers
service paymailclient.ServiceClient // Paymail service for handling Paymail requests
serverConfig *PaymailServerOptions // Server configuration if Paymail is enabled
}

// PaymailServerOptions is the options for the Paymail server
Expand Down Expand Up @@ -167,8 +169,8 @@ func NewClient(ctx context.Context, opts ...ClientOps) (ClientInterface, error)
return nil, err
}

// Load the Paymail client (if client does not exist)
if err = client.loadPaymailClient(); err != nil {
// Load the Paymail client and service (if does not exist)
if err = client.loadPaymailComponents(); err != nil {
return nil, err
}

Expand Down
22 changes: 20 additions & 2 deletions engine/client_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/bitcoin-sv/spv-wallet/engine/cluster"
"github.com/bitcoin-sv/spv-wallet/engine/datastore"
"github.com/bitcoin-sv/spv-wallet/engine/notifications"
paymailclient "github.com/bitcoin-sv/spv-wallet/engine/paymail"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
"github.com/bitcoin-sv/spv-wallet/engine/taskmanager"
"github.com/mrz1836/go-cachestore"
Expand Down Expand Up @@ -127,11 +128,28 @@ func (c *Client) GetWebhooks(ctx context.Context) ([]notifications.ModelWebhook,
return c.options.notifications.webhookManager.GetAll(ctx)
}

// loadPaymailClient will load the Paymail client
func (c *Client) loadPaymailClient() (err error) {
// loadPaymailComponents will load the Paymail client
func (c *Client) loadPaymailComponents() (err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
err = spverrors.Wrapf(e, "error when creating paymail components")
} else {
err = spverrors.Newf("error when creating paymail components: %v", r)
}
dorzepowski marked this conversation as resolved.
Show resolved Hide resolved
}
}()

// Only load if it's not set (the client can be overloaded)
if c.options.paymail.client == nil {
c.options.paymail.client, err = paymail.NewClient()
if err != nil {
return
}
}
if c.options.paymail.service == nil {
logger := c.Logger().With().Str("subservice", "paymail").Logger()
c.options.paymail.service = paymailclient.NewServiceClient(c.Cachestore(), c.options.paymail.client, logger)
}
return
}
Expand Down
14 changes: 14 additions & 0 deletions engine/client_paymail.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package engine

import (
"github.com/bitcoin-sv/go-paymail"
paymailclient "github.com/bitcoin-sv/spv-wallet/engine/paymail"
)

// PaymailClient will return the Paymail if it exists
Expand All @@ -12,6 +13,14 @@ func (c *Client) PaymailClient() paymail.ClientInterface {
return nil
}

// PaymailService will return the Paymail Service if it exists
func (c *Client) PaymailService() paymailclient.ServiceClient {
if c.options.paymail != nil && c.options.paymail.service != nil {
return c.options.paymail.ServiceClient()
}
return nil
}

// GetPaymailConfig will return the Paymail server config if it exists
func (c *Client) GetPaymailConfig() *PaymailServerOptions {
if c.options.paymail != nil && c.options.paymail.serverConfig != nil {
Expand All @@ -25,6 +34,11 @@ func (p *paymailOptions) Client() paymail.ClientInterface {
return p.client
}

// ServiceClient will return the paymail service client from the options struct
func (p *paymailOptions) ServiceClient() paymailclient.ServiceClient {
return p.service
}

// FromSender will return either the configuration value or the application default
func (p *paymailOptions) FromSender() string {
if len(p.serverConfig.DefaultFromPaymail) > 0 {
Expand Down
4 changes: 2 additions & 2 deletions engine/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func TestClient_GetPaymailConfig(t *testing.T) {
t.Run("valid paymail server config", func(t *testing.T) {
opts := DefaultClientOpts(false, true)
opts = append(opts, WithPaymailSupport(
[]string{testDomain},
[]string{"example.com"},
defaultSenderPaymail,
false, false,
))
Expand Down Expand Up @@ -234,7 +234,7 @@ func TestPaymailOptions_ServerConfig(t *testing.T) {
logger := zerolog.Nop()
opts := DefaultClientOpts(false, true)
opts = append(opts, WithPaymailSupport(
[]string{testDomain},
[]string{"example.com"},
defaultSenderPaymail,
false, false,
),
Expand Down
19 changes: 10 additions & 9 deletions engine/contact_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/bitcoin-sv/go-paymail"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
xtester "github.com/bitcoin-sv/spv-wallet/engine/tester/paymailmock"
"github.com/bitcoin-sv/spv-wallet/engine/utils"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/require"
Expand All @@ -23,7 +24,7 @@ func Test_ClientService_UpsertContact(t *testing.T) {
paymailAddr := "bran_the_broken@winterfell.com"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", true)
pt.setup("winterfell.com", true)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -65,7 +66,7 @@ func Test_ClientService_UpsertContact(t *testing.T) {
paymailAddr := "bran_the_broken@winterfell.com"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", false)
pt.setup("winterfell.com", false)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -94,7 +95,7 @@ func Test_ClientService_UpsertContact(t *testing.T) {
updatedFullname := "Brandon Stark"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", true)
pt.setup("winterfell.com", true)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -139,7 +140,7 @@ func Test_ClientService_UpsertContact(t *testing.T) {
updatedFullname := "Brandon Stark"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", true)
pt.setup("winterfell.com", true)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -187,7 +188,7 @@ func TestClientService_AddContactRequest(t *testing.T) {
paymailAddr := "sansa_stark@winterfell.com"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", true)
pt.setup("winterfell.com", true)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -216,7 +217,7 @@ func TestClientService_AddContactRequest(t *testing.T) {
paymailAddr := "sansa_stark@winterfell.com"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", true)
pt.setup("winterfell.com", true)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -258,7 +259,7 @@ func TestClientService_AddContactRequest(t *testing.T) {
updatedPki := "03c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90b"

pt := &paymailTestMock{}
pt.setup(t, "winterfell.com", true)
pt.setup("winterfell.com", true)
defer pt.cleanup()

pt.mockPki(paymailAddr, "04c85162f06f5391028211a3683d669301fc72085458ce94d0a9e77ba4ff61f90a")
Expand Down Expand Up @@ -305,7 +306,7 @@ type paymailTestMock struct {
paymailClient paymail.ClientInterface
}

func (p *paymailTestMock) setup(t *testing.T, domain string, supportPike bool) {
func (p *paymailTestMock) setup(domain string, supportPike bool) {
httpmock.Reset()
serverURL := "https://" + domain + "/api/v1/" + paymail.DefaultServiceName

Expand All @@ -327,7 +328,7 @@ func (p *paymailTestMock) setup(t *testing.T, domain string, supportPike bool) {
httpmock.RegisterResponder(http.MethodGet, wellKnownURL, wellKnownResponder)

p.serverURL = serverURL
p.paymailClient = newTestPaymailClient(t, []string{domain})
p.paymailClient = xtester.MockClient(domain)
}

func (p *paymailTestMock) cleanup() {
Expand Down
2 changes: 2 additions & 0 deletions engine/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/bitcoin-sv/spv-wallet/engine/datastore"
"github.com/bitcoin-sv/spv-wallet/engine/metrics"
"github.com/bitcoin-sv/spv-wallet/engine/notifications"
paymailclient "github.com/bitcoin-sv/spv-wallet/engine/paymail"
"github.com/bitcoin-sv/spv-wallet/engine/taskmanager"
"github.com/mrz1836/go-cachestore"
"github.com/rs/zerolog"
Expand Down Expand Up @@ -54,6 +55,7 @@ type ClientService interface {
Logger() *zerolog.Logger
Notifications() *notifications.Notifications
PaymailClient() paymail.ClientInterface
PaymailService() paymailclient.ServiceClient
Taskmanager() taskmanager.TaskEngine
}

Expand Down
24 changes: 6 additions & 18 deletions engine/model_draft_transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ func (m *DraftTransaction) processConfigOutputs(ctx context.Context) error {
if err == nil && len(paymails) != 0 {
paymailFrom = fmt.Sprintf("%s@%s", paymails[0].Alias, paymails[0].Domain)
}

paymailService := c.PaymailService()

// Special case where we are sending all funds to a single (address, paymail, handle)
if m.Configuration.SendAllTo != nil {
outputs := m.Configuration.Outputs
Expand All @@ -188,24 +191,14 @@ func (m *DraftTransaction) processConfigOutputs(ctx context.Context) error {
m.Configuration.SendAllTo.Satoshis = 0
m.Configuration.Outputs = []*TransactionOutput{m.Configuration.SendAllTo}

if err := m.Configuration.Outputs[0].processOutput(
ctx, c.Cachestore(),
c.PaymailClient(),
paymailFrom,
false,
); err != nil {
if err := m.Configuration.Outputs[0].processOutput(ctx, paymailService, paymailFrom, false); err != nil {
return err
}

// re-add the other outputs we had before
for _, output := range outputs {
output.UseForChange = false // make sure we do not add change to this output
if err := output.processOutput(
ctx, c.Cachestore(),
c.PaymailClient(),
paymailFrom,
true,
); err != nil {
if err := output.processOutput(ctx, paymailService, paymailFrom, true); err != nil {
return err
}
m.Configuration.Outputs = append(m.Configuration.Outputs, output)
Expand All @@ -220,12 +213,7 @@ func (m *DraftTransaction) processConfigOutputs(ctx context.Context) error {
}

// Process the outputs
if err := m.Configuration.Outputs[index].processOutput(
ctx, c.Cachestore(),
c.PaymailClient(),
paymailFrom,
true,
); err != nil {
if err := m.Configuration.Outputs[index].processOutput(ctx, paymailService, paymailFrom, true); err != nil {
return err
}
}
Expand Down
Loading
Loading