github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/invoice_storage.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package pingpong
    19  
    20  import (
    21  	"fmt"
    22  	"math/big"
    23  	"sync"
    24  
    25  	"github.com/mysteriumnetwork/node/identity"
    26  	"github.com/mysteriumnetwork/payments/crypto"
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  // ErrNotFound represents an error that indicates that there's no such invoice.
    31  var ErrNotFound = errors.New("entry does not exist")
    32  
    33  type bucketName string
    34  
    35  const sentInvoices bucketName = "sent_invoices"
    36  const agreementRBucket bucketName = "agreement_r"
    37  
    38  type genericInvoiceStorage interface {
    39  	StoreInvoice(bucket string, key string, invoice crypto.Invoice) error
    40  	GetInvoice(bucket string, key string) (crypto.Invoice, error)
    41  }
    42  
    43  type providerSpecificInvoiceStorage interface {
    44  	genericInvoiceStorage
    45  	StoreR(providerID identity.Identity, agreementID *big.Int, r string) error
    46  	GetR(providerID identity.Identity, agreementID *big.Int) (string, error)
    47  }
    48  
    49  // ProviderInvoiceStorage allows the provider to store sent invoices.
    50  type ProviderInvoiceStorage struct {
    51  	gis providerSpecificInvoiceStorage
    52  }
    53  
    54  // NewProviderInvoiceStorage returns a new instance of provider invoice storage.
    55  func NewProviderInvoiceStorage(gis providerSpecificInvoiceStorage) *ProviderInvoiceStorage {
    56  	return &ProviderInvoiceStorage{
    57  		gis: gis,
    58  	}
    59  }
    60  
    61  // Store stores the given invoice.
    62  func (pis *ProviderInvoiceStorage) Store(providerIdentity, consumerIdentity identity.Identity, invoice crypto.Invoice) error {
    63  	return pis.gis.StoreInvoice(string(sentInvoices), providerIdentity.Address+consumerIdentity.Address, invoice)
    64  }
    65  
    66  // Get returns the stored invoice.
    67  func (pis *ProviderInvoiceStorage) Get(providerIdentity, consumerIdentity identity.Identity) (crypto.Invoice, error) {
    68  	return pis.gis.GetInvoice(string(sentInvoices), providerIdentity.Address+consumerIdentity.Address)
    69  }
    70  
    71  // StoreR stores the given R.
    72  func (pis *ProviderInvoiceStorage) StoreR(providerID identity.Identity, agreementID *big.Int, r string) error {
    73  	return pis.gis.StoreR(providerID, agreementID, r)
    74  }
    75  
    76  // GetR gets the R for agreement.
    77  func (pis *ProviderInvoiceStorage) GetR(providerID identity.Identity, agreementID *big.Int) (string, error) {
    78  	return pis.gis.GetR(providerID, agreementID)
    79  }
    80  
    81  type persistentStorage interface {
    82  	GetValue(bucket string, key interface{}, to interface{}) error
    83  	SetValue(bucket string, key interface{}, to interface{}) error
    84  }
    85  
    86  // InvoiceStorage allows to store promises.
    87  type InvoiceStorage struct {
    88  	bolt persistentStorage
    89  	lock sync.Mutex
    90  }
    91  
    92  var errBoltNotFound = "not found"
    93  
    94  // NewInvoiceStorage creates a new instance of invoice storage.
    95  func NewInvoiceStorage(bolt persistentStorage) *InvoiceStorage {
    96  	return &InvoiceStorage{
    97  		bolt: bolt,
    98  	}
    99  }
   100  
   101  // StoreInvoice stores the given invoice in the given bucket with the identity as key.
   102  func (is *InvoiceStorage) StoreInvoice(bucket string, key string, invoice crypto.Invoice) error {
   103  	is.lock.Lock()
   104  	defer is.lock.Unlock()
   105  	return errors.Wrap(is.bolt.SetValue(bucket, key, invoice), "could not save invoice")
   106  }
   107  
   108  func (is *InvoiceStorage) getRKey(providerID identity.Identity, agreementID *big.Int) string {
   109  	return fmt.Sprintf("%v_%v", providerID.Address, agreementID)
   110  }
   111  
   112  // StoreR stores the given R.
   113  func (is *InvoiceStorage) StoreR(providerID identity.Identity, agreementID *big.Int, r string) error {
   114  	is.lock.Lock()
   115  	defer is.lock.Unlock()
   116  	err := is.bolt.SetValue(string(agreementRBucket), is.getRKey(providerID, agreementID), r)
   117  	return errors.Wrap(err, "could not save R")
   118  }
   119  
   120  // GetR returns the saved R.
   121  func (is *InvoiceStorage) GetR(providerID identity.Identity, agreementID *big.Int) (string, error) {
   122  	is.lock.Lock()
   123  	defer is.lock.Unlock()
   124  	var r string
   125  	err := is.bolt.GetValue(string(agreementRBucket), is.getRKey(providerID, agreementID), &r)
   126  	if err != nil {
   127  		// wrap the error to an error we can check for
   128  		if err.Error() == errBoltNotFound {
   129  			return "", ErrNotFound
   130  		}
   131  		return r, errors.Wrap(err, "could not get r")
   132  	}
   133  	return r, nil
   134  }
   135  
   136  // GetInvoice gets the corresponding invoice from storage.
   137  func (is *InvoiceStorage) GetInvoice(bucket string, key string) (crypto.Invoice, error) {
   138  	is.lock.Lock()
   139  	defer is.lock.Unlock()
   140  	invoice := &crypto.Invoice{}
   141  	err := is.bolt.GetValue(bucket, key, invoice)
   142  	if err != nil {
   143  		// wrap the error to an error we can check for
   144  		if err.Error() == errBoltNotFound {
   145  			err = ErrNotFound
   146  		} else {
   147  			err = errors.Wrap(err, "could not get invoice")
   148  		}
   149  	}
   150  	return *invoice, err
   151  }