github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/hermes_caller.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  	"context"
    22  	"encoding/hex"
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"math/big"
    28  	"net/http"
    29  	"strings"
    30  	"sync"
    31  	"time"
    32  
    33  	"github.com/cenkalti/backoff/v4"
    34  	"github.com/ethereum/go-ethereum/common"
    35  
    36  	"github.com/mysteriumnetwork/node/identity"
    37  	"github.com/mysteriumnetwork/node/requests"
    38  	"github.com/mysteriumnetwork/payments/crypto"
    39  )
    40  
    41  // HermesErrorResponse represents the errors that hermes returns
    42  type HermesErrorResponse struct {
    43  	CausedBy     string `json:"cause"`
    44  	ErrorMessage string `json:"message"`
    45  	ErrorData    string `json:"data"`
    46  	c            error
    47  }
    48  
    49  // Error returns the associated error
    50  func (aer HermesErrorResponse) Error() string {
    51  	return aer.c.Error()
    52  }
    53  
    54  // Cause returns the associated cause
    55  func (aer HermesErrorResponse) Cause() error {
    56  	return aer.c
    57  }
    58  
    59  // Unwrap unwraps the associated error
    60  func (aer HermesErrorResponse) Unwrap() error {
    61  	return aer.c
    62  }
    63  
    64  // Data returns the associated data
    65  func (aer HermesErrorResponse) Data() string {
    66  	return aer.ErrorData
    67  }
    68  
    69  // UnmarshalJSON unmarshals given data to HermesErrorResponse
    70  func (aer *HermesErrorResponse) UnmarshalJSON(data []byte) error {
    71  	var s struct {
    72  		CausedBy     string `json:"cause"`
    73  		ErrorMessage string `json:"message"`
    74  		ErrorData    string `json:"data"`
    75  	}
    76  
    77  	err := json.Unmarshal(data, &s)
    78  	if err != nil {
    79  		return fmt.Errorf("could not unmarshal error data %w", err)
    80  	}
    81  
    82  	aer.CausedBy = s.CausedBy
    83  	aer.ErrorMessage = s.ErrorMessage
    84  	aer.ErrorData = s.ErrorData
    85  
    86  	if v, ok := hermesCauseToError[s.CausedBy]; ok {
    87  		aer.c = v
    88  		return nil
    89  	}
    90  
    91  	return fmt.Errorf("received unknown error: %v", s.CausedBy)
    92  }
    93  
    94  type hermesError interface {
    95  	Error() string
    96  	Cause() error
    97  	Data() string
    98  }
    99  
   100  // HermesCaller represents the http caller for hermes.
   101  type HermesCaller struct {
   102  	transport     *requests.HTTPClient
   103  	hermesBaseURI string
   104  	cache         hermesCallerCache
   105  }
   106  
   107  // hermesCallerCache represents the cache for call responses
   108  type hermesCallerCache struct {
   109  	data map[string]hermesCallerCacheData
   110  	lock sync.RWMutex
   111  }
   112  
   113  // hermesCallerCacheData represents the cache data
   114  type hermesCallerCacheData struct {
   115  	info      *HermesUserInfo
   116  	err       error
   117  	updatedAt time.Time
   118  }
   119  
   120  // NewHermesCaller returns a new instance of hermes caller.
   121  func NewHermesCaller(transport *requests.HTTPClient, hermesBaseURI string) *HermesCaller {
   122  	return &HermesCaller{
   123  		transport:     transport,
   124  		hermesBaseURI: hermesBaseURI,
   125  		cache: hermesCallerCache{
   126  			data: make(map[string]hermesCallerCacheData),
   127  		},
   128  	}
   129  }
   130  
   131  // RequestPromise represents the request for a new hermes promise
   132  type RequestPromise struct {
   133  	ExchangeMessage crypto.ExchangeMessage `json:"exchange_message"`
   134  	TransactorFee   *big.Int               `json:"transactor_fee"`
   135  	RRecoveryData   string                 `json:"r_recovery_data"`
   136  }
   137  
   138  // RequestPromise requests a promise from hermes.
   139  func (ac *HermesCaller) RequestPromise(rp RequestPromise) (crypto.Promise, error) {
   140  	return ac.promiseRequest(rp, "request_promise")
   141  }
   142  
   143  func (ac *HermesCaller) promiseRequest(rp RequestPromise, endpoint string) (crypto.Promise, error) {
   144  	eback := backoff.NewConstantBackOff(time.Millisecond * 500)
   145  	boff := backoff.WithMaxRetries(eback, 3)
   146  	ctx, cancel := context.WithCancel(context.Background())
   147  	defer cancel()
   148  	boff = backoff.WithContext(boff, ctx)
   149  
   150  	res := crypto.Promise{}
   151  
   152  	return res, backoff.Retry(func() error {
   153  		req, err := requests.NewPostRequest(ac.hermesBaseURI, endpoint, rp)
   154  		if err != nil {
   155  			cancel()
   156  			return fmt.Errorf("could not form %v request: %w", endpoint, err)
   157  		}
   158  
   159  		err = ac.doRequest(req, &res)
   160  		if err != nil {
   161  			// if too many requests, retry
   162  			if errors.Is(err, ErrTooManyRequests) {
   163  				return err
   164  			}
   165  			// otherwise, do not retry anymore and return the error
   166  			cancel()
   167  			return fmt.Errorf("could not request promise: %w", err)
   168  		}
   169  		return nil
   170  	}, boff)
   171  }
   172  
   173  // PayAndSettle requests a promise from hermes.
   174  func (ac *HermesCaller) PayAndSettle(rp RequestPromise) (crypto.Promise, error) {
   175  	return ac.promiseRequest(rp, "pay_and_settle")
   176  }
   177  
   178  // SetPromiseFeeRequest represents the payload for changing a promise fee.
   179  type SetPromiseFeeRequest struct {
   180  	HermesPromise crypto.Promise `json:"hermes_promise"`
   181  	NewFee        *big.Int       `json:"new_fee"`
   182  }
   183  
   184  // UpdatePromiseFee calls hermes to update its promise with new fee.
   185  func (ac *HermesCaller) UpdatePromiseFee(promise crypto.Promise, newFee *big.Int) (crypto.Promise, error) {
   186  	req, err := requests.NewPostRequest(ac.hermesBaseURI, "change_promise_fee", SetPromiseFeeRequest{
   187  		HermesPromise: promise,
   188  		NewFee:        newFee,
   189  	})
   190  	if err != nil {
   191  		return crypto.Promise{}, fmt.Errorf("could not form change promise fee request: %w", err)
   192  	}
   193  
   194  	res := crypto.Promise{}
   195  	return res, ac.doRequest(req, &res)
   196  }
   197  
   198  // RevealObject represents the reveal request object.
   199  type RevealObject struct {
   200  	R           string
   201  	Provider    string
   202  	AgreementID *big.Int
   203  }
   204  
   205  // RevealR reveals hashlock key 'r' from 'provider' to the hermes for the agreement identified by 'agreementID'.
   206  func (ac *HermesCaller) RevealR(r, provider string, agreementID *big.Int) error {
   207  	eback := backoff.NewConstantBackOff(time.Millisecond * 500)
   208  	boff := backoff.WithMaxRetries(eback, 3)
   209  	ctx, cancel := context.WithCancel(context.Background())
   210  	defer cancel()
   211  	boff = backoff.WithContext(boff, ctx)
   212  	return backoff.Retry(func() error {
   213  		req, err := requests.NewPostRequest(ac.hermesBaseURI, "reveal_r", RevealObject{
   214  			R:           r,
   215  			Provider:    provider,
   216  			AgreementID: agreementID,
   217  		})
   218  		if err != nil {
   219  			cancel()
   220  			return fmt.Errorf("could not form reveal_r request: %w", err)
   221  		}
   222  
   223  		err = ac.doRequest(req, &RevealSuccess{})
   224  		if err != nil {
   225  			// if too many requests, retry
   226  			if errors.Is(err, ErrTooManyRequests) {
   227  				return err
   228  			}
   229  			// otherwise, do not retry anymore and return the error
   230  			cancel()
   231  			return fmt.Errorf("could not reveal R for hermes: %w", err)
   232  		}
   233  		return nil
   234  	}, boff)
   235  }
   236  
   237  // IsIdentityOffchain returns true if identity is considered offchain in hermes.
   238  func (ac *HermesCaller) IsIdentityOffchain(chainID int64, id string) (bool, error) {
   239  	data, err := ac.GetConsumerData(chainID, id, time.Second)
   240  	if err != nil {
   241  		if errors.Is(err, ErrHermesNotFound) {
   242  			return false, nil
   243  		}
   244  		return false, err
   245  	}
   246  
   247  	return data.IsOffchain, nil
   248  }
   249  
   250  type syncPromiseRequest struct {
   251  	ChannelID string   `json:"channel_id"`
   252  	ChainID   int64    `json:"chain_id"`
   253  	Amount    *big.Int `json:"amount"`
   254  	Fee       *big.Int `json:"fee"`
   255  	Hashlock  string   `json:"hashlock"`
   256  	Signature string   `json:"signature"`
   257  }
   258  
   259  // SyncProviderPromise syncs provider promise.
   260  func (ac *HermesCaller) SyncProviderPromise(promise crypto.Promise, signer identity.Signer) error {
   261  	toSend := syncPromiseRequest{
   262  		ChannelID: common.Bytes2Hex(promise.ChannelID),
   263  		ChainID:   promise.ChainID,
   264  		Amount:    promise.Amount,
   265  		Fee:       promise.Fee,
   266  		Hashlock:  common.Bytes2Hex(promise.Hashlock),
   267  		Signature: common.Bytes2Hex(promise.Signature),
   268  	}
   269  
   270  	req, err := requests.NewSignedPostRequest(ac.hermesBaseURI, "provider/sync_promise", toSend, signer)
   271  	if err != nil {
   272  		return fmt.Errorf("could not make promise sync request: %w", err)
   273  	}
   274  
   275  	err = ac.doRequest(req, map[string]any{})
   276  	if err != nil {
   277  		return fmt.Errorf("could not sync promise hermes: %w", err)
   278  	}
   279  
   280  	return nil
   281  }
   282  
   283  type refreshPromiseRequest struct {
   284  	ChainID       int64  `json:"chain_id"`
   285  	Identity      string `json:"identity"`
   286  	Hashlock      string `json:"hashlock"`
   287  	RRecoveryData string `json:"r_recovery_data"`
   288  }
   289  
   290  // RefreshLatestProviderPromise reissue latest promise with a new hashlock.
   291  func (ac *HermesCaller) RefreshLatestProviderPromise(chainID int64, id string, hashlock, recoveryData []byte, signer identity.Signer) (crypto.Promise, error) {
   292  	res := crypto.Promise{}
   293  	toSend := refreshPromiseRequest{
   294  		ChainID:       chainID,
   295  		Identity:      id,
   296  		Hashlock:      common.Bytes2Hex(hashlock),
   297  		RRecoveryData: common.Bytes2Hex(recoveryData),
   298  	}
   299  
   300  	req, err := requests.NewSignedPostRequest(ac.hermesBaseURI, "refresh_promise", toSend, signer)
   301  	if err != nil {
   302  		return res, fmt.Errorf("could not make promise sync request: %w", err)
   303  	}
   304  
   305  	err = ac.doRequest(req, &res)
   306  	if err != nil {
   307  		return res, fmt.Errorf("could not refresh promise: %w", err)
   308  	}
   309  
   310  	return res, nil
   311  }
   312  
   313  // GetConsumerData gets consumer data from hermes, use a negative cacheTime to force update
   314  func (ac *HermesCaller) GetConsumerData(chainID int64, id string, cacheTime time.Duration) (HermesUserInfo, error) {
   315  	if cacheTime > 0 {
   316  		cachedResponse, cachedError, ok := ac.getResponseFromCache(chainID, id, cacheTime)
   317  		if ok {
   318  			return cachedResponse, cachedError
   319  		}
   320  	}
   321  	req, err := requests.NewGetRequest(ac.hermesBaseURI, fmt.Sprintf("data/consumer/%v", id), nil)
   322  	if err != nil {
   323  		return HermesUserInfo{}, fmt.Errorf("could not form consumer data request: %w", err)
   324  	}
   325  	var resp map[int64]HermesUserInfo
   326  	err = ac.doRequest(req, &resp)
   327  	if err != nil {
   328  		if errors.Is(err, ErrHermesNotFound) {
   329  			// also save not found status
   330  			ac.setCacheData(chainID, id, nil, err)
   331  		}
   332  		return HermesUserInfo{}, fmt.Errorf("could not request consumer data from hermes: %w", err)
   333  	}
   334  
   335  	data, ok := resp[chainID]
   336  	if !ok {
   337  		return HermesUserInfo{}, fmt.Errorf("could not get data for chain ID: %d", chainID)
   338  	}
   339  
   340  	err = data.LatestPromise.isValid(id)
   341  	if err != nil {
   342  		return HermesUserInfo{}, fmt.Errorf("could not check promise validity: %w", err)
   343  	}
   344  
   345  	ac.setCacheData(chainID, id, &data, nil)
   346  
   347  	return data, nil
   348  }
   349  
   350  func (ac *HermesCaller) setCacheData(chainID int64, id string, data *HermesUserInfo, err error) {
   351  	ac.cache.lock.Lock()
   352  	defer ac.cache.lock.Unlock()
   353  
   354  	ac.cache.data[getCacheKey(chainID, id)] = hermesCallerCacheData{
   355  		updatedAt: time.Now(),
   356  		info:      data,
   357  		err:       err,
   358  	}
   359  }
   360  
   361  // GetProviderData gets provider data from hermes
   362  func (ac *HermesCaller) GetProviderData(chainID int64, id string) (HermesUserInfo, error) {
   363  	return ac.getProviderData(chainID, id)
   364  }
   365  
   366  // ProviderPromiseAmountUnsafe returns the provider promise amount.
   367  // If can also return `nil` as the result if no promise exists.
   368  func (ac *HermesCaller) ProviderPromiseAmountUnsafe(chainID int64, id string) (*big.Int, error) {
   369  	d, err := ac.getProviderData(chainID, id)
   370  	if err != nil {
   371  		if errors.Is(err, ErrHermesNotFound) {
   372  			return nil, nil
   373  		}
   374  
   375  		return nil, err
   376  	}
   377  
   378  	return d.LatestPromise.Amount, nil
   379  }
   380  
   381  func (ac *HermesCaller) getProviderData(chainID int64, id string) (HermesUserInfo, error) {
   382  	req, err := requests.NewGetRequest(ac.hermesBaseURI, fmt.Sprintf("data/provider/%v", id), nil)
   383  	if err != nil {
   384  		return HermesUserInfo{}, fmt.Errorf("could not form consumer data request: %w", err)
   385  	}
   386  	var resp map[int64]HermesUserInfo
   387  	err = ac.doRequest(req, &resp)
   388  	if err != nil {
   389  		return HermesUserInfo{}, fmt.Errorf("could not request consumer data from hermes: %w", err)
   390  	}
   391  
   392  	data, ok := resp[chainID]
   393  	if !ok {
   394  		return HermesUserInfo{}, fmt.Errorf("could not get data for chain ID: %d", chainID)
   395  	}
   396  
   397  	return data, nil
   398  }
   399  
   400  func (ac *HermesCaller) doRequest(req *http.Request, to any) error {
   401  	resp, err := ac.transport.Do(req)
   402  	if err != nil {
   403  		return fmt.Errorf("could not execute request: %w", err)
   404  	}
   405  	defer resp.Body.Close()
   406  	body, err := io.ReadAll(resp.Body)
   407  	if err != nil {
   408  		return fmt.Errorf("could not read response body: %w", err)
   409  	}
   410  
   411  	if resp.StatusCode >= 200 && resp.StatusCode <= 300 {
   412  		// parse response
   413  		err = json.Unmarshal(body, &to)
   414  		if err != nil {
   415  			return fmt.Errorf("could not unmarshal response body: %w", err)
   416  		}
   417  		return nil
   418  	}
   419  
   420  	// parse error body
   421  	hermesError := HermesErrorResponse{}
   422  	if string(body) == "" {
   423  		hermesError.ErrorMessage = "Unknown error"
   424  		return hermesError
   425  	}
   426  
   427  	err = json.Unmarshal(body, &hermesError)
   428  	if err != nil {
   429  		return fmt.Errorf("could not unmarshal error body: %w", err)
   430  	}
   431  
   432  	return hermesError
   433  }
   434  
   435  func (ac *HermesCaller) getResponseFromCache(chainID int64, identity string, cacheDuration time.Duration) (HermesUserInfo, error, bool) {
   436  	ac.cache.lock.RLock()
   437  	defer ac.cache.lock.RUnlock()
   438  
   439  	cacheKey := getCacheKey(chainID, identity)
   440  	cachedResponse, ok := ac.cache.data[cacheKey]
   441  	if ok && cachedResponse.updatedAt.Add(cacheDuration).After(time.Now()) {
   442  		if cachedResponse.err != nil {
   443  			return HermesUserInfo{}, cachedResponse.err, true
   444  		}
   445  		return *cachedResponse.info, nil, true
   446  	}
   447  	return HermesUserInfo{}, nil, false
   448  }
   449  
   450  // HermesUserInfo represents the consumer data
   451  type HermesUserInfo struct {
   452  	Identity         string        `json:"Identity"`
   453  	Beneficiary      string        `json:"Beneficiary"`
   454  	ChannelID        string        `json:"ChannelID"`
   455  	Balance          *big.Int      `json:"Balance"`
   456  	Settled          *big.Int      `json:"Settled"`
   457  	Stake            *big.Int      `json:"Stake"`
   458  	LatestPromise    LatestPromise `json:"LatestPromise"`
   459  	LatestSettlement time.Time     `json:"LatestSettlement"`
   460  	IsOffchain       bool          `json:"IsOffchain"`
   461  }
   462  
   463  func (cd *HermesUserInfo) fillZerosIfBigIntNull() *HermesUserInfo {
   464  	if cd.Balance == nil {
   465  		cd.Balance = big.NewInt(0)
   466  	}
   467  
   468  	if cd.Settled == nil {
   469  		cd.Settled = big.NewInt(0)
   470  	}
   471  
   472  	if cd.Stake == nil {
   473  		cd.Stake = big.NewInt(0)
   474  	}
   475  
   476  	if cd.LatestPromise.Amount == nil {
   477  		cd.LatestPromise.Amount = big.NewInt(0)
   478  	}
   479  
   480  	if cd.LatestPromise.Fee == nil {
   481  		cd.LatestPromise.Fee = big.NewInt(0)
   482  	}
   483  
   484  	return cd
   485  }
   486  
   487  // LatestPromise represents the latest promise
   488  type LatestPromise struct {
   489  	ChainID   int64    `json:"ChainID"`
   490  	ChannelID string   `json:"ChannelID"`
   491  	Amount    *big.Int `json:"Amount"`
   492  	Fee       *big.Int `json:"Fee"`
   493  	Hashlock  string   `json:"Hashlock"`
   494  	Signature string   `json:"Signature"`
   495  }
   496  
   497  // isValid checks if the promise is really issued by the given identity
   498  func (lp LatestPromise) isValid(id string) error {
   499  	// if we've not promised anything, that's fine for us.
   500  	// handles the case when we've just registered the identity.
   501  	if lp.Amount == nil || lp.Amount.Cmp(new(big.Int)) == 0 {
   502  		return nil
   503  	}
   504  
   505  	decodedChannelID, err := hex.DecodeString(strings.TrimPrefix(lp.ChannelID, "0x"))
   506  	if err != nil {
   507  		return fmt.Errorf("could not decode channel ID: %w", err)
   508  	}
   509  	decodedHashlock, err := hex.DecodeString(strings.TrimPrefix(lp.Hashlock, "0x"))
   510  	if err != nil {
   511  		return fmt.Errorf("could not decode hashlock: %w", err)
   512  	}
   513  	decodedSignature, err := hex.DecodeString(strings.TrimPrefix(lp.Signature, "0x"))
   514  	if err != nil {
   515  		return fmt.Errorf("could not decode signature: %w", err)
   516  	}
   517  
   518  	p := crypto.Promise{
   519  		ChainID:   lp.ChainID,
   520  		ChannelID: decodedChannelID,
   521  		Amount:    lp.Amount,
   522  		Fee:       lp.Fee,
   523  		Hashlock:  decodedHashlock,
   524  		Signature: decodedSignature,
   525  	}
   526  
   527  	if !p.IsPromiseValid(common.HexToAddress(id)) {
   528  		return fmt.Errorf("promise issued by wrong identity. Expected %q", id)
   529  	}
   530  
   531  	return nil
   532  }
   533  
   534  func getCacheKey(chainID int64, identity string) string {
   535  	return fmt.Sprintf("%d:%s", chainID, strings.ToLower(identity))
   536  }
   537  
   538  // RevealSuccess represents the reveal success response from hermes
   539  type RevealSuccess struct {
   540  	Message string `json:"message"`
   541  }
   542  
   543  // ErrHermesInvalidSignature indicates that an invalid signature was sent.
   544  var ErrHermesInvalidSignature = errors.New("invalid signature")
   545  
   546  // ErrHermesInternal represents an internal error.
   547  var ErrHermesInternal = errors.New("internal error")
   548  
   549  // ErrHermesPreviousRNotRevealed represents that a previous R has not been revealed yet. No actions will be possible before the R is revealed.
   550  var ErrHermesPreviousRNotRevealed = errors.New("previous R not revealed")
   551  
   552  // ErrHermesPaymentValueTooLow indicates that the agreement total has decreased as opposed to increasing.
   553  var ErrHermesPaymentValueTooLow = errors.New("payment value too low")
   554  
   555  // ErrHermesProviderBalanceExhausted indicates that the provider has run out of stake and a rebalance is needed.
   556  var ErrHermesProviderBalanceExhausted = errors.New("provider balance exhausted, please rebalance your channel")
   557  
   558  // ErrHermesPromiseValueTooLow represents an error where the consumer sent a promise with a decreasing total.
   559  var ErrHermesPromiseValueTooLow = errors.New("promise value too low")
   560  
   561  // ErrHermesOverspend indicates that the consumer has overspent his balance.
   562  var ErrHermesOverspend = errors.New("consumer does not have enough balance and is overspending")
   563  
   564  // ErrHermesMalformedJSON indicates that the provider has sent an invalid json in the request.
   565  var ErrHermesMalformedJSON = errors.New("malformed json")
   566  
   567  // ErrNeedsRRecovery indicates that we need to recover R.
   568  var ErrNeedsRRecovery = errors.New("r recovery required")
   569  
   570  // ErrInvalidPreviuosLatestPromise represents an error where historical promise data is invalid resulting in a non functional provider or consumner.
   571  var ErrInvalidPreviuosLatestPromise = errors.New("invalid previuos latest promise, impossible to issue new one")
   572  
   573  // ErrHermesNoPreviousPromise indicates that we have no previous knowledge of a promise for the provider.
   574  var ErrHermesNoPreviousPromise = errors.New("no previous promise found")
   575  
   576  // ErrHermesHashlockMissmatch occurs when an expected hashlock does not match the one sent by provider.
   577  var ErrHermesHashlockMissmatch = errors.New("hashlock missmatch")
   578  
   579  // ErrHermesNotFound occurs when a requested resource is not found
   580  var ErrHermesNotFound = errors.New("resource not found")
   581  
   582  // ErrTooManyRequests occurs when we call the reveal R or request promise errors asynchronously at the same time.
   583  var ErrTooManyRequests = errors.New("too many simultaneous requests")
   584  
   585  // ErrConsumerUnregistered indicates that the consumer is not registered.
   586  var ErrConsumerUnregistered = errors.New("consumer unregistered")
   587  
   588  var hermesCauseToError = map[string]error{
   589  	ErrHermesInvalidSignature.Error():         ErrHermesInvalidSignature,
   590  	ErrHermesInternal.Error():                 ErrHermesInternal,
   591  	ErrHermesPreviousRNotRevealed.Error():     ErrHermesPreviousRNotRevealed,
   592  	ErrHermesPaymentValueTooLow.Error():       ErrHermesPaymentValueTooLow,
   593  	ErrHermesProviderBalanceExhausted.Error(): ErrHermesProviderBalanceExhausted,
   594  	ErrHermesPromiseValueTooLow.Error():       ErrHermesPromiseValueTooLow,
   595  	ErrHermesOverspend.Error():                ErrHermesOverspend,
   596  	ErrHermesMalformedJSON.Error():            ErrHermesMalformedJSON,
   597  	ErrHermesNoPreviousPromise.Error():        ErrHermesNoPreviousPromise,
   598  	ErrHermesHashlockMissmatch.Error():        ErrHermesHashlockMissmatch,
   599  	ErrHermesNotFound.Error():                 ErrHermesNotFound,
   600  	ErrNeedsRRecovery.Error():                 ErrNeedsRRecovery,
   601  	ErrTooManyRequests.Error():                ErrTooManyRequests,
   602  	ErrConsumerUnregistered.Error():           ErrConsumerUnregistered,
   603  	ErrInvalidPreviuosLatestPromise.Error():   ErrInvalidPreviuosLatestPromise,
   604  }
   605  
   606  type rRecoveryDetails struct {
   607  	R           string   `json:"r"`
   608  	AgreementID *big.Int `json:"agreement_id"`
   609  }