github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/connection/connection_validator.go (about)

     1  /*
     2   * Copyright (C) 2020 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 connection
    19  
    20  import (
    21  	"math/big"
    22  
    23  	"github.com/mysteriumnetwork/node/identity"
    24  	"github.com/mysteriumnetwork/node/market"
    25  )
    26  
    27  type consumerBalanceGetter interface {
    28  	NeedsForceSync(chainID int64, id identity.Identity) bool
    29  	GetBalance(chainID int64, id identity.Identity) *big.Int
    30  	ForceBalanceUpdate(chainID int64, id identity.Identity) *big.Int
    31  }
    32  
    33  type unlockChecker interface {
    34  	IsUnlocked(id string) bool
    35  }
    36  
    37  // Validator validates pre connection conditions.
    38  type Validator struct {
    39  	consumerBalanceGetter consumerBalanceGetter
    40  	unlockChecker         unlockChecker
    41  }
    42  
    43  // NewValidator returns a new instance of connection validator.
    44  func NewValidator(consumerBalanceGetter consumerBalanceGetter, unlockChecker unlockChecker) *Validator {
    45  	return &Validator{
    46  		consumerBalanceGetter: consumerBalanceGetter,
    47  		unlockChecker:         unlockChecker,
    48  	}
    49  }
    50  
    51  // validateBalance checks if consumer has enough money for given proposal.
    52  func (v *Validator) validateBalance(chainID int64, consumerID identity.Identity, price market.Price) bool {
    53  	balance := v.consumerBalanceGetter.GetBalance(chainID, consumerID)
    54  
    55  	if v.consumerBalanceGetter.NeedsForceSync(chainID, consumerID) {
    56  		balance = v.consumerBalanceGetter.ForceBalanceUpdate(chainID, consumerID)
    57  	}
    58  
    59  	if perHour := price.PricePerHour; perHour.Cmp(big.NewInt(0)) > 0 {
    60  		perMin := new(big.Int).Div(perHour, big.NewInt(60))
    61  		if balance.Cmp(perMin) < 0 {
    62  			return false
    63  		}
    64  	}
    65  
    66  	if perGiB := price.PricePerGiB; perGiB.Cmp(big.NewInt(0)) > 0 {
    67  		perMiB := new(big.Int).Div(perGiB, big.NewInt(1024))
    68  		if balance.Cmp(perMiB) < 0 {
    69  			return false
    70  		}
    71  	}
    72  
    73  	return true
    74  }
    75  
    76  // isUnlocked checks if the identity is unlocked or not.
    77  func (v *Validator) isUnlocked(consumerID identity.Identity) bool {
    78  	return v.unlockChecker.IsUnlocked(consumerID.Address)
    79  }
    80  
    81  // Validate checks whether the pre-connection conditions are fulfilled.
    82  func (v *Validator) Validate(chainID int64, consumerID identity.Identity, price market.Price) error {
    83  	if !v.isUnlocked(consumerID) {
    84  		return ErrUnlockRequired
    85  	}
    86  
    87  	if !v.validateBalance(chainID, consumerID, price) {
    88  		return ErrInsufficientBalance
    89  	}
    90  
    91  	return nil
    92  }