github.com/Finschia/finschia-sdk@v0.49.1/x/bank/types/balance_test.go (about)

     1  package types_test
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/Finschia/finschia-sdk/crypto/keys/ed25519"
    10  	sdk "github.com/Finschia/finschia-sdk/types"
    11  	bank "github.com/Finschia/finschia-sdk/x/bank/types"
    12  )
    13  
    14  func TestBalanceValidate(t *testing.T) {
    15  	testCases := []struct {
    16  		name    string
    17  		balance bank.Balance
    18  		expErr  bool
    19  	}{
    20  		{
    21  			"valid balance",
    22  			bank.Balance{
    23  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    24  				Coins:   sdk.Coins{sdk.NewInt64Coin("uatom", 1)},
    25  			},
    26  			false,
    27  		},
    28  		{"empty balance", bank.Balance{}, true},
    29  		{
    30  			"nil balance coins",
    31  			bank.Balance{
    32  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    33  			},
    34  			false,
    35  		},
    36  		{
    37  			"dup coins",
    38  			bank.Balance{
    39  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    40  				Coins: sdk.Coins{
    41  					sdk.NewInt64Coin("uatom", 1),
    42  					sdk.NewInt64Coin("uatom", 1),
    43  				},
    44  			},
    45  			true,
    46  		},
    47  		{
    48  			"invalid coin denom",
    49  			bank.Balance{
    50  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    51  				Coins: sdk.Coins{
    52  					sdk.Coin{Denom: "", Amount: sdk.OneInt()},
    53  				},
    54  			},
    55  			true,
    56  		},
    57  		{
    58  			"negative coin",
    59  			bank.Balance{
    60  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    61  				Coins: sdk.Coins{
    62  					sdk.Coin{Denom: "uatom", Amount: sdk.NewInt(-1)},
    63  				},
    64  			},
    65  			true,
    66  		},
    67  		{
    68  			"0 value coin",
    69  			bank.Balance{
    70  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    71  				Coins: sdk.Coins{
    72  					sdk.NewInt64Coin("atom", 0),
    73  					sdk.NewInt64Coin("zatom", 2),
    74  				},
    75  			},
    76  			true,
    77  		},
    78  		{
    79  			"unsorted coins",
    80  			bank.Balance{
    81  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    82  				Coins: sdk.Coins{
    83  					sdk.NewInt64Coin("atom", 2),
    84  					sdk.NewInt64Coin("zatom", 2),
    85  					sdk.NewInt64Coin("batom", 12),
    86  				},
    87  			},
    88  			true,
    89  		},
    90  		{
    91  			"valid sorted coins",
    92  			bank.Balance{
    93  				Address: "link1yq8lgssgxlx9smjhes6ryjasmqmd3ts2p6925r",
    94  				Coins: sdk.Coins{
    95  					sdk.NewInt64Coin("atom", 2),
    96  					sdk.NewInt64Coin("batom", 12),
    97  					sdk.NewInt64Coin("zatom", 2),
    98  				},
    99  			},
   100  			false,
   101  		},
   102  	}
   103  
   104  	for _, tc := range testCases {
   105  		t.Run(tc.name, func(t *testing.T) {
   106  			err := tc.balance.Validate()
   107  
   108  			if tc.expErr {
   109  				require.Error(t, err)
   110  			} else {
   111  				require.NoError(t, err)
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func TestBalance_GetAddress(t *testing.T) {
   118  	tests := []struct {
   119  		name      string
   120  		Address   string
   121  		wantPanic bool
   122  	}{
   123  		{"empty address", "", true},
   124  		{"malformed address", "invalid", true},
   125  		{"valid address", "link1vy0ga0klndqy92ceqehfkvgmn4t94ete4mhemy", false},
   126  	}
   127  	for _, tt := range tests {
   128  		t.Run(tt.name, func(t *testing.T) {
   129  			b := bank.Balance{Address: tt.Address}
   130  			if tt.wantPanic {
   131  				require.Panics(t, func() { b.GetAddress() })
   132  			} else {
   133  				require.False(t, b.GetAddress().Empty())
   134  			}
   135  		})
   136  	}
   137  }
   138  
   139  func TestSanitizeBalances(t *testing.T) {
   140  	// 1. Generate balances
   141  	tokens := sdk.TokensFromConsensusPower(81, sdk.DefaultPowerReduction)
   142  	coin := sdk.NewCoin("benchcoin", tokens)
   143  	coins := sdk.Coins{coin}
   144  	addrs, _ := makeRandomAddressesAndPublicKeys(20)
   145  
   146  	var balances []bank.Balance
   147  	for _, addr := range addrs {
   148  		balances = append(balances, bank.Balance{
   149  			Address: addr.String(),
   150  			Coins:   coins,
   151  		})
   152  	}
   153  	// 2. Sort the values.
   154  	sorted := bank.SanitizeGenesisBalances(balances)
   155  
   156  	// 3. Compare and ensure that all the values are sorted in ascending order.
   157  	// Invariant after sorting:
   158  	//    a[i] <= a[i+1...n]
   159  	for i := 0; i < len(sorted); i++ {
   160  		ai := sorted[i]
   161  		// Ensure that every single value that comes after i is less than it.
   162  		for j := i + 1; j < len(sorted); j++ {
   163  			aj := sorted[j]
   164  
   165  			if got := bytes.Compare(ai.GetAddress(), aj.GetAddress()); got > 0 {
   166  				t.Errorf("Balance(%d) > Balance(%d)", i, j)
   167  			}
   168  		}
   169  	}
   170  }
   171  
   172  func makeRandomAddressesAndPublicKeys(n int) (accL []sdk.AccAddress, pkL []*ed25519.PubKey) {
   173  	for i := 0; i < n; i++ {
   174  		pk := ed25519.GenPrivKey().PubKey().(*ed25519.PubKey)
   175  		pkL = append(pkL, pk)
   176  		accL = append(accL, sdk.AccAddress(pk.Address()))
   177  	}
   178  	return accL, pkL
   179  }
   180  
   181  var sink, revert interface{}
   182  
   183  func BenchmarkSanitizeBalances500(b *testing.B) {
   184  	benchmarkSanitizeBalances(b, 500)
   185  }
   186  
   187  func BenchmarkSanitizeBalances1000(b *testing.B) {
   188  	benchmarkSanitizeBalances(b, 1000)
   189  }
   190  
   191  func benchmarkSanitizeBalances(b *testing.B, nAddresses int) {
   192  	b.Helper()
   193  	b.ReportAllocs()
   194  	tokens := sdk.TokensFromConsensusPower(81, sdk.DefaultPowerReduction)
   195  	coin := sdk.NewCoin("benchcoin", tokens)
   196  	coins := sdk.Coins{coin}
   197  	addrs, _ := makeRandomAddressesAndPublicKeys(nAddresses)
   198  
   199  	b.ResetTimer()
   200  	for i := 0; i < b.N; i++ {
   201  		var balances []bank.Balance
   202  		for _, addr := range addrs {
   203  			balances = append(balances, bank.Balance{
   204  				Address: addr.String(),
   205  				Coins:   coins,
   206  			})
   207  		}
   208  		sink = bank.SanitizeGenesisBalances(balances)
   209  	}
   210  	if sink == nil {
   211  		b.Fatal("Benchmark did not run")
   212  	}
   213  	sink = revert
   214  }