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 }