github.com/Finschia/finschia-sdk@v0.48.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  		tc := tc
   106  		t.Run(tc.name, func(t *testing.T) {
   107  			err := tc.balance.Validate()
   108  
   109  			if tc.expErr {
   110  				require.Error(t, err)
   111  			} else {
   112  				require.NoError(t, err)
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestBalance_GetAddress(t *testing.T) {
   119  	tests := []struct {
   120  		name      string
   121  		Address   string
   122  		wantPanic bool
   123  	}{
   124  		{"empty address", "", true},
   125  		{"malformed address", "invalid", true},
   126  		{"valid address", "link1vy0ga0klndqy92ceqehfkvgmn4t94ete4mhemy", false},
   127  	}
   128  	for _, tt := range tests {
   129  		tt := tt
   130  		t.Run(tt.name, func(t *testing.T) {
   131  			b := bank.Balance{Address: tt.Address}
   132  			if tt.wantPanic {
   133  				require.Panics(t, func() { b.GetAddress() })
   134  			} else {
   135  				require.False(t, b.GetAddress().Empty())
   136  			}
   137  		})
   138  	}
   139  }
   140  
   141  func TestSanitizeBalances(t *testing.T) {
   142  	// 1. Generate balances
   143  	tokens := sdk.TokensFromConsensusPower(81, sdk.DefaultPowerReduction)
   144  	coin := sdk.NewCoin("benchcoin", tokens)
   145  	coins := sdk.Coins{coin}
   146  	addrs, _ := makeRandomAddressesAndPublicKeys(20)
   147  
   148  	var balances []bank.Balance
   149  	for _, addr := range addrs {
   150  		balances = append(balances, bank.Balance{
   151  			Address: addr.String(),
   152  			Coins:   coins,
   153  		})
   154  	}
   155  	// 2. Sort the values.
   156  	sorted := bank.SanitizeGenesisBalances(balances)
   157  
   158  	// 3. Compare and ensure that all the values are sorted in ascending order.
   159  	// Invariant after sorting:
   160  	//    a[i] <= a[i+1...n]
   161  	for i := 0; i < len(sorted); i++ {
   162  		ai := sorted[i]
   163  		// Ensure that every single value that comes after i is less than it.
   164  		for j := i + 1; j < len(sorted); j++ {
   165  			aj := sorted[j]
   166  
   167  			if got := bytes.Compare(ai.GetAddress(), aj.GetAddress()); got > 0 {
   168  				t.Errorf("Balance(%d) > Balance(%d)", i, j)
   169  			}
   170  		}
   171  	}
   172  }
   173  
   174  func makeRandomAddressesAndPublicKeys(n int) (accL []sdk.AccAddress, pkL []*ed25519.PubKey) {
   175  	for i := 0; i < n; i++ {
   176  		pk := ed25519.GenPrivKey().PubKey().(*ed25519.PubKey)
   177  		pkL = append(pkL, pk)
   178  		accL = append(accL, sdk.AccAddress(pk.Address()))
   179  	}
   180  	return accL, pkL
   181  }
   182  
   183  var sink, revert interface{}
   184  
   185  func BenchmarkSanitizeBalances500(b *testing.B) {
   186  	benchmarkSanitizeBalances(b, 500)
   187  }
   188  
   189  func BenchmarkSanitizeBalances1000(b *testing.B) {
   190  	benchmarkSanitizeBalances(b, 1000)
   191  }
   192  
   193  func benchmarkSanitizeBalances(b *testing.B, nAddresses int) {
   194  	b.ReportAllocs()
   195  	tokens := sdk.TokensFromConsensusPower(81, sdk.DefaultPowerReduction)
   196  	coin := sdk.NewCoin("benchcoin", tokens)
   197  	coins := sdk.Coins{coin}
   198  	addrs, _ := makeRandomAddressesAndPublicKeys(nAddresses)
   199  
   200  	b.ResetTimer()
   201  	for i := 0; i < b.N; i++ {
   202  		var balances []bank.Balance
   203  		for _, addr := range addrs {
   204  			balances = append(balances, bank.Balance{
   205  				Address: addr.String(),
   206  				Coins:   coins,
   207  			})
   208  		}
   209  		sink = bank.SanitizeGenesisBalances(balances)
   210  	}
   211  	if sink == nil {
   212  		b.Fatal("Benchmark did not run")
   213  	}
   214  	sink = revert
   215  }