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 }