github.com/ethersphere/bee/v2@v2.2.0/pkg/settlement/swap/swap.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package swap
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"math/big"
    12  
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethersphere/bee/v2/pkg/log"
    15  	"github.com/ethersphere/bee/v2/pkg/postage/postagecontract"
    16  	"github.com/ethersphere/bee/v2/pkg/settlement"
    17  	"github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook"
    18  	"github.com/ethersphere/bee/v2/pkg/settlement/swap/swapprotocol"
    19  	"github.com/ethersphere/bee/v2/pkg/storage"
    20  	"github.com/ethersphere/bee/v2/pkg/swarm"
    21  )
    22  
    23  // loggerName is the tree path name of the logger for this package.
    24  const loggerName = "swap"
    25  
    26  var (
    27  	// ErrWrongChequebook is the error if a peer uses a different chequebook from before.
    28  	ErrWrongChequebook = errors.New("wrong chequebook")
    29  	// ErrUnknownBeneficary is the error if a peer has never announced a beneficiary.
    30  	ErrUnknownBeneficary = errors.New("unknown beneficiary for peer")
    31  	// ErrChequeValueTooLow is the error a peer issued a cheque not covering 1 accounting credit
    32  	ErrChequeValueTooLow = errors.New("cheque value too low")
    33  	ErrNoChequebook      = errors.New("no chequebook")
    34  )
    35  
    36  type Interface interface {
    37  	settlement.Interface
    38  	// LastSentCheque returns the last sent cheque for the peer
    39  	LastSentCheque(peer swarm.Address) (*chequebook.SignedCheque, error)
    40  	// LastSentCheques returns the list of last sent cheques for all peers
    41  	LastSentCheques() (map[string]*chequebook.SignedCheque, error)
    42  	// LastReceivedCheque returns the last received cheque for the peer
    43  	LastReceivedCheque(peer swarm.Address) (*chequebook.SignedCheque, error)
    44  	// LastReceivedCheques returns the list of last received cheques for all peers
    45  	LastReceivedCheques() (map[string]*chequebook.SignedCheque, error)
    46  	// CashCheque sends a cashing transaction for the last cheque of the peer
    47  	CashCheque(ctx context.Context, peer swarm.Address) (common.Hash, error)
    48  	// CashoutStatus gets the status of the latest cashout transaction for the peers chequebook
    49  	CashoutStatus(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error)
    50  }
    51  
    52  // Service is the implementation of the swap settlement layer.
    53  type Service struct {
    54  	proto          swapprotocol.Interface
    55  	logger         log.Logger
    56  	store          storage.StateStorer
    57  	accounting     settlement.Accounting
    58  	metrics        metrics
    59  	chequebook     chequebook.Service
    60  	chequeStore    chequebook.ChequeStore
    61  	cashout        chequebook.CashoutService
    62  	addressbook    Addressbook
    63  	networkID      uint64
    64  	cashoutAddress common.Address
    65  }
    66  
    67  // New creates a new swap Service.
    68  func New(proto swapprotocol.Interface, logger log.Logger, store storage.StateStorer, chequebook chequebook.Service, chequeStore chequebook.ChequeStore, addressbook Addressbook, networkID uint64, cashout chequebook.CashoutService, accounting settlement.Accounting, cashoutAddress common.Address) *Service {
    69  	return &Service{
    70  		proto:          proto,
    71  		logger:         logger.WithName(loggerName).Register(),
    72  		store:          store,
    73  		metrics:        newMetrics(),
    74  		chequebook:     chequebook,
    75  		chequeStore:    chequeStore,
    76  		addressbook:    addressbook,
    77  		networkID:      networkID,
    78  		cashout:        cashout,
    79  		accounting:     accounting,
    80  		cashoutAddress: cashoutAddress,
    81  	}
    82  }
    83  
    84  // ReceiveCheque is called by the swap protocol if a cheque is received.
    85  func (s *Service) ReceiveCheque(ctx context.Context, peer swarm.Address, cheque *chequebook.SignedCheque, exchangeRate, deduction *big.Int) (err error) {
    86  	// check this is the same chequebook for this peer as previously
    87  	expectedChequebook, known, err := s.addressbook.Chequebook(peer)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	if known && expectedChequebook != cheque.Chequebook {
    92  		return ErrWrongChequebook
    93  	}
    94  
    95  	receivedAmount, err := s.chequeStore.ReceiveCheque(ctx, cheque, exchangeRate, deduction)
    96  	if err != nil {
    97  		s.metrics.ChequesRejected.Inc()
    98  		return fmt.Errorf("rejecting cheque: %w", err)
    99  	}
   100  
   101  	if deduction.Cmp(big.NewInt(0)) > 0 {
   102  		err = s.addressbook.AddDeductionFor(peer)
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  
   108  	decreasedAmount := new(big.Int).Sub(receivedAmount, deduction)
   109  	amount := new(big.Int).Div(decreasedAmount, exchangeRate)
   110  
   111  	if !known {
   112  		err = s.addressbook.PutChequebook(peer, cheque.Chequebook)
   113  		if err != nil {
   114  			return err
   115  		}
   116  	}
   117  
   118  	tot, _ := big.NewFloat(0).SetInt(receivedAmount).Float64()
   119  	s.metrics.TotalReceived.Add(tot)
   120  	s.metrics.ChequesReceived.Inc()
   121  
   122  	return s.accounting.NotifyPaymentReceived(peer, amount)
   123  }
   124  
   125  // Pay initiates a payment to the given peer
   126  func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount *big.Int) {
   127  	var err error
   128  	defer func() {
   129  		if err != nil {
   130  			s.accounting.NotifyPaymentSent(peer, amount, err)
   131  		}
   132  	}()
   133  	if s.chequebook == nil {
   134  		err = ErrNoChequebook
   135  		return
   136  	}
   137  	beneficiary, known, err := s.addressbook.Beneficiary(peer)
   138  	if err != nil {
   139  		return
   140  	}
   141  	if !known {
   142  		err = ErrUnknownBeneficary
   143  		return
   144  	}
   145  
   146  	balance, err := s.proto.EmitCheque(ctx, peer, beneficiary, amount, s.chequebook.Issue)
   147  
   148  	if err != nil {
   149  		return
   150  	}
   151  
   152  	bal, _ := big.NewFloat(0).SetInt(balance).Float64()
   153  	s.metrics.AvailableBalance.Set(bal)
   154  	s.accounting.NotifyPaymentSent(peer, amount, nil)
   155  	amountFloat, _ := big.NewFloat(0).SetInt(amount).Float64()
   156  	s.metrics.TotalSent.Add(amountFloat)
   157  	s.metrics.ChequesSent.Inc()
   158  }
   159  
   160  func (s *Service) SetAccounting(accounting settlement.Accounting) {
   161  	s.accounting = accounting
   162  }
   163  
   164  // TotalSent returns the total amount sent to a peer
   165  func (s *Service) TotalSent(peer swarm.Address) (totalSent *big.Int, err error) {
   166  	beneficiary, known, err := s.addressbook.Beneficiary(peer)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	if !known {
   171  		return nil, settlement.ErrPeerNoSettlements
   172  	}
   173  	if s.chequebook == nil {
   174  		return big.NewInt(0), nil
   175  	}
   176  	cheque, err := s.chequebook.LastCheque(beneficiary)
   177  	if err != nil {
   178  		if errors.Is(err, chequebook.ErrNoCheque) {
   179  			return nil, settlement.ErrPeerNoSettlements
   180  		}
   181  		return nil, err
   182  	}
   183  	return cheque.CumulativePayout, nil
   184  }
   185  
   186  // TotalReceived returns the total amount received from a peer
   187  func (s *Service) TotalReceived(peer swarm.Address) (totalReceived *big.Int, err error) {
   188  	chequebookAddress, known, err := s.addressbook.Chequebook(peer)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	if !known {
   193  		return nil, settlement.ErrPeerNoSettlements
   194  	}
   195  
   196  	cheque, err := s.chequeStore.LastCheque(chequebookAddress)
   197  	if err != nil {
   198  		if errors.Is(err, chequebook.ErrNoCheque) {
   199  			return nil, settlement.ErrPeerNoSettlements
   200  		}
   201  		return nil, err
   202  	}
   203  	return cheque.CumulativePayout, nil
   204  }
   205  
   206  // SettlementsSent returns sent settlements for each individual known peer
   207  func (s *Service) SettlementsSent() (map[string]*big.Int, error) {
   208  	result := make(map[string]*big.Int)
   209  	if s.chequebook == nil {
   210  		return result, nil
   211  	}
   212  	cheques, err := s.chequebook.LastCheques()
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	for beneficiary, cheque := range cheques {
   218  		peer, known, err := s.addressbook.BeneficiaryPeer(beneficiary)
   219  		if err != nil {
   220  			return nil, err
   221  		}
   222  		if !known {
   223  			continue
   224  		}
   225  		result[peer.String()] = cheque.CumulativePayout
   226  	}
   227  
   228  	return result, nil
   229  }
   230  
   231  // SettlementsReceived returns received settlements for each individual known peer.
   232  func (s *Service) SettlementsReceived() (map[string]*big.Int, error) {
   233  	result := make(map[string]*big.Int)
   234  	cheques, err := s.chequeStore.LastCheques()
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	for chequebook, cheque := range cheques {
   240  		peer, known, err := s.addressbook.ChequebookPeer(chequebook)
   241  		if err != nil {
   242  			return nil, err
   243  		}
   244  		if !known {
   245  			continue
   246  		}
   247  		result[peer.String()] = cheque.CumulativePayout
   248  	}
   249  	return result, err
   250  }
   251  
   252  // Handshake is called by the swap protocol when a handshake is received.
   253  func (s *Service) Handshake(peer swarm.Address, beneficiary common.Address) error {
   254  	loggerV1 := s.logger.V(1).Register()
   255  
   256  	oldPeer, known, err := s.addressbook.BeneficiaryPeer(beneficiary)
   257  	if err != nil {
   258  		return err
   259  	}
   260  	if known && !peer.Equal(oldPeer) {
   261  		s.logger.Debug("migrating swap addresses", "old_peer_address", oldPeer, "new_peer_address", peer)
   262  		return s.addressbook.MigratePeer(oldPeer, peer)
   263  	}
   264  
   265  	_, known, err = s.addressbook.Beneficiary(peer)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	if !known {
   270  		loggerV1.Debug("initial swap handshake", "peer_address", peer, "beneficiary_address", beneficiary)
   271  		return s.addressbook.PutBeneficiary(peer, beneficiary)
   272  	}
   273  
   274  	return nil
   275  }
   276  
   277  // LastSentCheque returns the last sent cheque for the peer
   278  func (s *Service) LastSentCheque(peer swarm.Address) (*chequebook.SignedCheque, error) {
   279  
   280  	common, known, err := s.addressbook.Beneficiary(peer)
   281  
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  
   286  	if !known {
   287  		return nil, chequebook.ErrNoCheque
   288  	}
   289  
   290  	if s.chequebook == nil {
   291  		return nil, ErrNoChequebook
   292  	}
   293  
   294  	return s.chequebook.LastCheque(common)
   295  }
   296  
   297  // LastReceivedCheque returns the last received cheque for the peer
   298  func (s *Service) LastReceivedCheque(peer swarm.Address) (*chequebook.SignedCheque, error) {
   299  
   300  	common, known, err := s.addressbook.Chequebook(peer)
   301  
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	if !known {
   307  		return nil, chequebook.ErrNoCheque
   308  	}
   309  
   310  	return s.chequeStore.LastCheque(common)
   311  }
   312  
   313  // LastSentCheques returns the list of last sent cheques for all peers
   314  func (s *Service) LastSentCheques() (map[string]*chequebook.SignedCheque, error) {
   315  	if s.chequebook == nil {
   316  		return nil, ErrNoChequebook
   317  	}
   318  	lastcheques, err := s.chequebook.LastCheques()
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  
   323  	resultmap := make(map[string]*chequebook.SignedCheque, len(lastcheques))
   324  
   325  	for i, j := range lastcheques {
   326  		addr, known, err := s.addressbook.BeneficiaryPeer(i)
   327  		if err == nil && known {
   328  			resultmap[addr.String()] = j
   329  		}
   330  	}
   331  
   332  	return resultmap, nil
   333  }
   334  
   335  // LastReceivedCheques returns the list of last received cheques for all peers
   336  func (s *Service) LastReceivedCheques() (map[string]*chequebook.SignedCheque, error) {
   337  	lastcheques, err := s.chequeStore.LastCheques()
   338  	if err != nil {
   339  		return nil, err
   340  	}
   341  
   342  	resultmap := make(map[string]*chequebook.SignedCheque, len(lastcheques))
   343  
   344  	for i, j := range lastcheques {
   345  		addr, known, err := s.addressbook.ChequebookPeer(i)
   346  		if err == nil && known {
   347  			resultmap[addr.String()] = j
   348  		}
   349  	}
   350  
   351  	return resultmap, nil
   352  }
   353  
   354  // CashCheque sends a cashing transaction for the last cheque of the peer
   355  func (s *Service) CashCheque(ctx context.Context, peer swarm.Address) (common.Hash, error) {
   356  	chequebookAddress, known, err := s.addressbook.Chequebook(peer)
   357  	if err != nil {
   358  		return common.Hash{}, err
   359  	}
   360  	if !known {
   361  		return common.Hash{}, chequebook.ErrNoCheque
   362  	}
   363  	return s.cashout.CashCheque(ctx, chequebookAddress, s.cashoutAddress)
   364  }
   365  
   366  // CashoutStatus gets the status of the latest cashout transaction for the peers chequebook
   367  func (s *Service) CashoutStatus(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) {
   368  	chequebookAddress, known, err := s.addressbook.Chequebook(peer)
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  	if !known {
   373  		return nil, chequebook.ErrNoCheque
   374  	}
   375  	return s.cashout.CashoutStatus(ctx, chequebookAddress)
   376  }
   377  
   378  func (s *Service) GetDeductionForPeer(peer swarm.Address) (bool, error) {
   379  	return s.addressbook.GetDeductionFor(peer)
   380  }
   381  
   382  func (s *Service) GetDeductionByPeer(peer swarm.Address) (bool, error) {
   383  	return s.addressbook.GetDeductionBy(peer)
   384  }
   385  
   386  func (s *Service) AddDeductionByPeer(peer swarm.Address) error {
   387  	return s.addressbook.AddDeductionBy(peer)
   388  }
   389  
   390  type NoOpSwap struct {
   391  }
   392  
   393  func (*NoOpSwap) TotalSent(peer swarm.Address) (totalSent *big.Int, err error) {
   394  	return nil, postagecontract.ErrChainDisabled
   395  }
   396  
   397  // TotalReceived returns the total amount received from a peer
   398  func (*NoOpSwap) TotalReceived(peer swarm.Address) (totalSent *big.Int, err error) {
   399  	return nil, postagecontract.ErrChainDisabled
   400  }
   401  
   402  // SettlementsSent returns sent settlements for each individual known peer
   403  func (*NoOpSwap) SettlementsSent() (map[string]*big.Int, error) {
   404  	return nil, postagecontract.ErrChainDisabled
   405  }
   406  
   407  // SettlementsReceived returns received settlements for each individual known peer
   408  func (*NoOpSwap) SettlementsReceived() (map[string]*big.Int, error) {
   409  	return nil, postagecontract.ErrChainDisabled
   410  }
   411  
   412  func (*NoOpSwap) LastSentCheque(peer swarm.Address) (*chequebook.SignedCheque, error) {
   413  	return nil, postagecontract.ErrChainDisabled
   414  }
   415  
   416  // LastSentCheques returns the list of last sent cheques for all peers
   417  func (*NoOpSwap) LastSentCheques() (map[string]*chequebook.SignedCheque, error) {
   418  	return nil, postagecontract.ErrChainDisabled
   419  }
   420  
   421  // LastReceivedCheque returns the last received cheque for the peer
   422  func (*NoOpSwap) LastReceivedCheque(peer swarm.Address) (*chequebook.SignedCheque, error) {
   423  	return nil, postagecontract.ErrChainDisabled
   424  }
   425  
   426  // LastReceivedCheques returns the list of last received cheques for all peers
   427  func (*NoOpSwap) LastReceivedCheques() (map[string]*chequebook.SignedCheque, error) {
   428  	return nil, postagecontract.ErrChainDisabled
   429  }
   430  
   431  // CashCheque sends a cashing transaction for the last cheque of the peer
   432  func (*NoOpSwap) CashCheque(ctx context.Context, peer swarm.Address) (common.Hash, error) {
   433  	return common.Hash{}, postagecontract.ErrChainDisabled
   434  }
   435  
   436  // CashoutStatus gets the status of the latest cashout transaction for the peers chequebook
   437  func (*NoOpSwap) CashoutStatus(ctx context.Context, peer swarm.Address) (*chequebook.CashoutStatus, error) {
   438  	return nil, postagecontract.ErrChainDisabled
   439  }