github.com/ava-labs/avalanchego@v1.11.11/vms/components/gas/dimensions_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package gas
     5  
     6  import (
     7  	"math"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	safemath "github.com/ava-labs/avalanchego/utils/math"
    13  )
    14  
    15  func Test_Dimensions_Add(t *testing.T) {
    16  	tests := []struct {
    17  		name        string
    18  		lhs         Dimensions
    19  		rhs         []*Dimensions
    20  		expected    Dimensions
    21  		expectedErr error
    22  	}{
    23  		{
    24  			name: "no error single entry",
    25  			lhs: Dimensions{
    26  				Bandwidth: 1,
    27  				DBRead:    2,
    28  				DBWrite:   3,
    29  				Compute:   4,
    30  			},
    31  			rhs: []*Dimensions{
    32  				{
    33  					Bandwidth: 10,
    34  					DBRead:    20,
    35  					DBWrite:   30,
    36  					Compute:   40,
    37  				},
    38  			},
    39  			expected: Dimensions{
    40  				Bandwidth: 11,
    41  				DBRead:    22,
    42  				DBWrite:   33,
    43  				Compute:   44,
    44  			},
    45  			expectedErr: nil,
    46  		},
    47  		{
    48  			name: "no error multiple entries",
    49  			lhs: Dimensions{
    50  				Bandwidth: 1,
    51  				DBRead:    2,
    52  				DBWrite:   3,
    53  				Compute:   4,
    54  			},
    55  			rhs: []*Dimensions{
    56  				{
    57  					Bandwidth: 10,
    58  					DBRead:    20,
    59  					DBWrite:   30,
    60  					Compute:   40,
    61  				},
    62  				{
    63  					Bandwidth: 100,
    64  					DBRead:    200,
    65  					DBWrite:   300,
    66  					Compute:   400,
    67  				},
    68  			},
    69  			expected: Dimensions{
    70  				Bandwidth: 111,
    71  				DBRead:    222,
    72  				DBWrite:   333,
    73  				Compute:   444,
    74  			},
    75  			expectedErr: nil,
    76  		},
    77  		{
    78  			name: "bandwidth overflow",
    79  			lhs: Dimensions{
    80  				Bandwidth: math.MaxUint64,
    81  				DBRead:    2,
    82  				DBWrite:   3,
    83  				Compute:   4,
    84  			},
    85  			rhs: []*Dimensions{
    86  				{
    87  					Bandwidth: 10,
    88  					DBRead:    20,
    89  					DBWrite:   30,
    90  					Compute:   40,
    91  				},
    92  			},
    93  			expected: Dimensions{
    94  				Bandwidth: 0,
    95  				DBRead:    2,
    96  				DBWrite:   3,
    97  				Compute:   4,
    98  			},
    99  			expectedErr: safemath.ErrOverflow,
   100  		},
   101  		{
   102  			name: "db read overflow",
   103  			lhs: Dimensions{
   104  				Bandwidth: 1,
   105  				DBRead:    math.MaxUint64,
   106  				DBWrite:   3,
   107  				Compute:   4,
   108  			},
   109  			rhs: []*Dimensions{
   110  				{
   111  					Bandwidth: 10,
   112  					DBRead:    20,
   113  					DBWrite:   30,
   114  					Compute:   40,
   115  				},
   116  			},
   117  			expected: Dimensions{
   118  				Bandwidth: 11,
   119  				DBRead:    0,
   120  				DBWrite:   3,
   121  				Compute:   4,
   122  			},
   123  			expectedErr: safemath.ErrOverflow,
   124  		},
   125  		{
   126  			name: "db write overflow",
   127  			lhs: Dimensions{
   128  				Bandwidth: 1,
   129  				DBRead:    2,
   130  				DBWrite:   math.MaxUint64,
   131  				Compute:   4,
   132  			},
   133  			rhs: []*Dimensions{
   134  				{
   135  					Bandwidth: 10,
   136  					DBRead:    20,
   137  					DBWrite:   30,
   138  					Compute:   40,
   139  				},
   140  			},
   141  			expected: Dimensions{
   142  				Bandwidth: 11,
   143  				DBRead:    22,
   144  				DBWrite:   0,
   145  				Compute:   4,
   146  			},
   147  			expectedErr: safemath.ErrOverflow,
   148  		},
   149  		{
   150  			name: "compute overflow",
   151  			lhs: Dimensions{
   152  				Bandwidth: 1,
   153  				DBRead:    2,
   154  				DBWrite:   3,
   155  				Compute:   math.MaxUint64,
   156  			},
   157  			rhs: []*Dimensions{
   158  				{
   159  					Bandwidth: 10,
   160  					DBRead:    20,
   161  					DBWrite:   30,
   162  					Compute:   40,
   163  				},
   164  			},
   165  			expected: Dimensions{
   166  				Bandwidth: 11,
   167  				DBRead:    22,
   168  				DBWrite:   33,
   169  				Compute:   0,
   170  			},
   171  			expectedErr: safemath.ErrOverflow,
   172  		},
   173  	}
   174  	for _, test := range tests {
   175  		t.Run(test.name, func(t *testing.T) {
   176  			require := require.New(t)
   177  
   178  			actual, err := test.lhs.Add(test.rhs...)
   179  			require.ErrorIs(err, test.expectedErr)
   180  			require.Equal(test.expected, actual)
   181  		})
   182  	}
   183  }
   184  
   185  func Test_Dimensions_Sub(t *testing.T) {
   186  	tests := []struct {
   187  		name        string
   188  		lhs         Dimensions
   189  		rhs         []*Dimensions
   190  		expected    Dimensions
   191  		expectedErr error
   192  	}{
   193  		{
   194  			name: "no error single entry",
   195  			lhs: Dimensions{
   196  				Bandwidth: 11,
   197  				DBRead:    22,
   198  				DBWrite:   33,
   199  				Compute:   44,
   200  			},
   201  			rhs: []*Dimensions{
   202  				{
   203  					Bandwidth: 1,
   204  					DBRead:    2,
   205  					DBWrite:   3,
   206  					Compute:   4,
   207  				},
   208  			},
   209  			expected: Dimensions{
   210  				Bandwidth: 10,
   211  				DBRead:    20,
   212  				DBWrite:   30,
   213  				Compute:   40,
   214  			},
   215  			expectedErr: nil,
   216  		},
   217  		{
   218  			name: "no error multiple entries",
   219  			lhs: Dimensions{
   220  				Bandwidth: 11,
   221  				DBRead:    22,
   222  				DBWrite:   33,
   223  				Compute:   44,
   224  			},
   225  			rhs: []*Dimensions{
   226  				{
   227  					Bandwidth: 1,
   228  					DBRead:    2,
   229  					DBWrite:   3,
   230  					Compute:   4,
   231  				},
   232  				{
   233  					Bandwidth: 5,
   234  					DBRead:    5,
   235  					DBWrite:   5,
   236  					Compute:   5,
   237  				},
   238  			},
   239  			expected: Dimensions{
   240  				Bandwidth: 5,
   241  				DBRead:    15,
   242  				DBWrite:   25,
   243  				Compute:   35,
   244  			},
   245  			expectedErr: nil,
   246  		},
   247  		{
   248  			name: "bandwidth underflow",
   249  			lhs: Dimensions{
   250  				Bandwidth: 11,
   251  				DBRead:    22,
   252  				DBWrite:   33,
   253  				Compute:   44,
   254  			},
   255  			rhs: []*Dimensions{
   256  				{
   257  					Bandwidth: math.MaxUint64,
   258  					DBRead:    2,
   259  					DBWrite:   3,
   260  					Compute:   4,
   261  				},
   262  			},
   263  			expected: Dimensions{
   264  				Bandwidth: 0,
   265  				DBRead:    22,
   266  				DBWrite:   33,
   267  				Compute:   44,
   268  			},
   269  			expectedErr: safemath.ErrUnderflow,
   270  		},
   271  		{
   272  			name: "db read underflow",
   273  			lhs: Dimensions{
   274  				Bandwidth: 11,
   275  				DBRead:    22,
   276  				DBWrite:   33,
   277  				Compute:   44,
   278  			},
   279  			rhs: []*Dimensions{
   280  				{
   281  					Bandwidth: 1,
   282  					DBRead:    math.MaxUint64,
   283  					DBWrite:   3,
   284  					Compute:   4,
   285  				},
   286  			},
   287  			expected: Dimensions{
   288  				Bandwidth: 10,
   289  				DBRead:    0,
   290  				DBWrite:   33,
   291  				Compute:   44,
   292  			},
   293  			expectedErr: safemath.ErrUnderflow,
   294  		},
   295  		{
   296  			name: "db write underflow",
   297  			lhs: Dimensions{
   298  				Bandwidth: 11,
   299  				DBRead:    22,
   300  				DBWrite:   33,
   301  				Compute:   44,
   302  			},
   303  			rhs: []*Dimensions{
   304  				{
   305  					Bandwidth: 1,
   306  					DBRead:    2,
   307  					DBWrite:   math.MaxUint64,
   308  					Compute:   4,
   309  				},
   310  			},
   311  			expected: Dimensions{
   312  				Bandwidth: 10,
   313  				DBRead:    20,
   314  				DBWrite:   0,
   315  				Compute:   44,
   316  			},
   317  			expectedErr: safemath.ErrUnderflow,
   318  		},
   319  		{
   320  			name: "compute underflow",
   321  			lhs: Dimensions{
   322  				Bandwidth: 11,
   323  				DBRead:    22,
   324  				DBWrite:   33,
   325  				Compute:   44,
   326  			},
   327  			rhs: []*Dimensions{
   328  				{
   329  					Bandwidth: 1,
   330  					DBRead:    2,
   331  					DBWrite:   3,
   332  					Compute:   math.MaxUint64,
   333  				},
   334  			},
   335  			expected: Dimensions{
   336  				Bandwidth: 10,
   337  				DBRead:    20,
   338  				DBWrite:   30,
   339  				Compute:   0,
   340  			},
   341  			expectedErr: safemath.ErrUnderflow,
   342  		},
   343  	}
   344  	for _, test := range tests {
   345  		t.Run(test.name, func(t *testing.T) {
   346  			require := require.New(t)
   347  
   348  			actual, err := test.lhs.Sub(test.rhs...)
   349  			require.ErrorIs(err, test.expectedErr)
   350  			require.Equal(test.expected, actual)
   351  		})
   352  	}
   353  }
   354  
   355  func Test_Dimensions_ToGas(t *testing.T) {
   356  	tests := []struct {
   357  		name        string
   358  		units       Dimensions
   359  		weights     Dimensions
   360  		expected    Gas
   361  		expectedErr error
   362  	}{
   363  		{
   364  			name: "no error",
   365  			units: Dimensions{
   366  				Bandwidth: 1,
   367  				DBRead:    2,
   368  				DBWrite:   3,
   369  				Compute:   4,
   370  			},
   371  			weights: Dimensions{
   372  				Bandwidth: 1000,
   373  				DBRead:    100,
   374  				DBWrite:   10,
   375  				Compute:   1,
   376  			},
   377  			expected:    1*1000 + 2*100 + 3*10 + 4*1,
   378  			expectedErr: nil,
   379  		},
   380  		{
   381  			name: "multiplication overflow",
   382  			units: Dimensions{
   383  				Bandwidth: 2,
   384  				DBRead:    1,
   385  				DBWrite:   1,
   386  				Compute:   1,
   387  			},
   388  			weights: Dimensions{
   389  				Bandwidth: math.MaxUint64,
   390  				DBRead:    1,
   391  				DBWrite:   1,
   392  				Compute:   1,
   393  			},
   394  			expected:    0,
   395  			expectedErr: safemath.ErrOverflow,
   396  		},
   397  		{
   398  			name: "addition overflow",
   399  			units: Dimensions{
   400  				Bandwidth: 1,
   401  				DBRead:    1,
   402  				DBWrite:   0,
   403  				Compute:   0,
   404  			},
   405  			weights: Dimensions{
   406  				Bandwidth: math.MaxUint64,
   407  				DBRead:    math.MaxUint64,
   408  				DBWrite:   1,
   409  				Compute:   1,
   410  			},
   411  			expected:    0,
   412  			expectedErr: safemath.ErrOverflow,
   413  		},
   414  	}
   415  	for _, test := range tests {
   416  		t.Run(test.name, func(t *testing.T) {
   417  			require := require.New(t)
   418  
   419  			actual, err := test.units.ToGas(test.weights)
   420  			require.ErrorIs(err, test.expectedErr)
   421  			require.Equal(test.expected, actual)
   422  
   423  			actual, err = test.weights.ToGas(test.units)
   424  			require.ErrorIs(err, test.expectedErr)
   425  			require.Equal(test.expected, actual)
   426  		})
   427  	}
   428  }
   429  
   430  func Benchmark_Dimensions_Add(b *testing.B) {
   431  	lhs := Dimensions{600, 10, 10, 1000}
   432  	rhs := []*Dimensions{
   433  		{1, 1, 1, 1},
   434  		{10, 10, 10, 10},
   435  		{100, 100, 100, 100},
   436  		{200, 200, 200, 200},
   437  		{500, 500, 500, 500},
   438  		{1_000, 1_000, 1_000, 1_000},
   439  		{10_000, 10_000, 10_000, 10_000},
   440  	}
   441  
   442  	b.Run("single", func(b *testing.B) {
   443  		for i := 0; i < b.N; i++ {
   444  			_, _ = lhs.Add(rhs[0])
   445  		}
   446  	})
   447  
   448  	b.Run("multiple", func(b *testing.B) {
   449  		for i := 0; i < b.N; i++ {
   450  			_, _ = lhs.Add(rhs[0], rhs[1], rhs[2], rhs[3], rhs[4], rhs[5], rhs[6])
   451  		}
   452  	})
   453  }
   454  
   455  func Benchmark_Dimensions_Sub(b *testing.B) {
   456  	lhs := Dimensions{10_000, 10_000, 10_000, 100_000}
   457  	rhs := []*Dimensions{
   458  		{1, 1, 1, 1},
   459  		{10, 10, 10, 10},
   460  		{100, 100, 100, 100},
   461  		{200, 200, 200, 200},
   462  		{500, 500, 500, 500},
   463  		{1_000, 1_000, 1_000, 1_000},
   464  	}
   465  
   466  	b.Run("single", func(b *testing.B) {
   467  		for i := 0; i < b.N; i++ {
   468  			_, _ = lhs.Sub(rhs[0])
   469  		}
   470  	})
   471  
   472  	b.Run("multiple", func(b *testing.B) {
   473  		for i := 0; i < b.N; i++ {
   474  			_, _ = lhs.Sub(rhs[0], rhs[1], rhs[2], rhs[3], rhs[4], rhs[5])
   475  		}
   476  	})
   477  }