code.vegaprotocol.io/vega@v0.79.0/core/integration/helpers/account_changes.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package helpers 17 18 import ( 19 "fmt" 20 "sort" 21 22 "code.vegaprotocol.io/vega/core/collateral" 23 "code.vegaprotocol.io/vega/libs/num" 24 types "code.vegaprotocol.io/vega/protos/vega" 25 ) 26 27 // ReconcileAccountChanges takes account balances before the step, modifies them based on supplied transfer, deposits, withdrawals as well as insurance pool balance changes intitiated by test code (not regular flow), and then compares them to account balances after the step. 28 func ReconcileAccountChanges(collateralEngine *collateral.Engine, before, after []types.Account, insurancePoolDeposits map[string]*num.Int, transfersInBetween []*types.LedgerEntry) error { 29 bmp, err := mapFromAccount(before) 30 if err != nil { 31 return err 32 } 33 amp, err := mapFromAccount(after) 34 if err != nil { 35 return err 36 } 37 38 for acc, amt := range insurancePoolDeposits { 39 if _, ok := bmp[acc]; !ok { 40 bmp[acc] = num.IntZero() 41 } 42 bmp[acc].Add(amt) 43 } 44 45 for _, t := range transfersInBetween { 46 amt, err := stringToBigInt(t.Amount) 47 if err != nil { 48 return err 49 } 50 from := t.FromAccount.ID() 51 to := t.ToAccount.ID() 52 if amt.IsPositive() { 53 if _, ok := bmp[from]; !ok { 54 bmp[from] = num.IntZero() 55 } 56 if _, ok := bmp[to]; !ok { 57 bmp[to] = num.IntZero() 58 } 59 bmp[from].Sub(amt) 60 bmp[to].Add(amt) 61 } 62 } 63 64 keys := make([]string, 0, len(amp)) 65 for k := range amp { 66 keys = append(keys, k) 67 } 68 69 sort.Strings(keys) 70 71 for _, acc := range keys { 72 value := amp[acc] 73 reconciledValue := bmp[acc] 74 if !value.IsZero() && (reconciledValue == nil || !reconciledValue.EQ(value)) { 75 return fmt.Errorf("'%s' account balance: '%v', expected: '%v'", acc, value, reconciledValue) 76 } 77 } 78 79 return checkAgainstCollateralEngineState(collateralEngine, amp) 80 } 81 82 func checkAgainstCollateralEngineState(collateralEngine *collateral.Engine, accounts map[string]*num.Int) error { 83 for id, expectedValue := range accounts { 84 acc, err := collateralEngine.GetAccountByID(id) 85 if err != nil { 86 if expectedValue.IsZero() { 87 continue 88 } 89 return err 90 } 91 actualValue := acc.Balance 92 if acc.Type == types.AccountType_ACCOUNT_TYPE_EXTERNAL { 93 // we don't sent account events for external accounts 94 continue 95 } 96 if !expectedValue.EQ(num.IntFromUint(actualValue, true)) { 97 return fmt.Errorf("invalid balance for account '%s', expected: '%s', got: '%s'", id, expectedValue, actualValue) 98 } 99 } 100 return nil 101 } 102 103 func mapFromAccount(accs []types.Account) (map[string]*num.Int, error) { 104 mp := make(map[string]*num.Int, len(accs)) 105 var err error 106 for _, a := range accs { 107 mp[a.GetId()], err = stringToBigInt(a.Balance) 108 if err != nil { 109 return nil, err 110 } 111 } 112 return mp, nil 113 } 114 115 func stringToBigInt(amnt string) (*num.Int, error) { 116 amt, b := num.IntFromString(amnt, 10) 117 if b { 118 return nil, fmt.Errorf("error encountered during conversion of '%s' to num.Int", amnt) 119 } 120 return amt, nil 121 }