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  }