code.vegaprotocol.io/vega@v0.79.0/core/staking/accounting_test.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 staking_test
    17  
    18  import (
    19  	"context"
    20  	"encoding/hex"
    21  	"testing"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/core/broker/mocks"
    25  	"code.vegaprotocol.io/vega/core/staking"
    26  	smocks "code.vegaprotocol.io/vega/core/staking/mocks"
    27  	"code.vegaprotocol.io/vega/core/types"
    28  	"code.vegaprotocol.io/vega/libs/num"
    29  	"code.vegaprotocol.io/vega/logging"
    30  
    31  	"github.com/golang/mock/gomock"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  type accountingTest struct {
    37  	*staking.Accounting
    38  	log     *logging.Logger
    39  	ctrl    *gomock.Controller
    40  	tsvc    *smocks.MockTimeService
    41  	broker  *mocks.MockBroker
    42  	evtfwd  *smocks.MockEvtForwarder
    43  	witness *smocks.MockWitness
    44  
    45  	onTick func(context.Context, time.Time)
    46  }
    47  
    48  func getAccountingTest(t *testing.T) *accountingTest {
    49  	t.Helper()
    50  	log := logging.NewTestLogger()
    51  	ctrl := gomock.NewController(t)
    52  	ts := smocks.NewMockTimeService(ctrl)
    53  	broker := mocks.NewMockBroker(ctrl)
    54  	evtfwd := smocks.NewMockEvtForwarder(ctrl)
    55  	witness := smocks.NewMockWitness(ctrl)
    56  	ethsource := smocks.NewMockEthereumEventSource(ctrl)
    57  	var onTick func(context.Context, time.Time)
    58  
    59  	return &accountingTest{
    60  		Accounting: staking.NewAccounting(
    61  			log, staking.NewDefaultConfig(), ts, broker, nil, evtfwd, witness, true, ethsource),
    62  		log:     log,
    63  		ctrl:    ctrl,
    64  		tsvc:    ts,
    65  		broker:  broker,
    66  		evtfwd:  evtfwd,
    67  		witness: witness,
    68  		onTick:  onTick,
    69  	}
    70  }
    71  
    72  func TestStakingAccounting(t *testing.T) {
    73  	t.Run("error party don't exists", testPartyDontExists)
    74  	t.Run("get available balance at", testAccountingGetAvailableBalanceAt)
    75  	t.Run("get available balance in range", testAccountingGetAvailableBalanceInRange)
    76  	t.Run("generate Hash", testAccountingGenerateHash)
    77  }
    78  
    79  func testPartyDontExists(t *testing.T) {
    80  	acc := getAccountingTest(t)
    81  	defer acc.ctrl.Finish()
    82  
    83  	balance, err := acc.GetAvailableBalance("nope")
    84  	assert.EqualError(t, err, staking.ErrNoBalanceForParty.Error())
    85  	assert.Equal(t, num.UintZero(), balance)
    86  	balance, err = acc.GetAvailableBalanceAt("nope", time.Unix(10, 0))
    87  	assert.EqualError(t, err, staking.ErrNoBalanceForParty.Error())
    88  	assert.Equal(t, num.UintZero(), balance)
    89  	balance, err = acc.GetAvailableBalanceInRange("nope", time.Unix(10, 0), time.Unix(20, 0))
    90  	assert.EqualError(t, err, staking.ErrNoBalanceForParty.Error())
    91  	assert.Equal(t, num.UintZero(), balance)
    92  }
    93  
    94  func testAccountingGetAvailableBalanceInRange(t *testing.T) {
    95  	acc := getAccountingTest(t)
    96  	defer acc.ctrl.Finish()
    97  	cases := []struct {
    98  		evt    types.StakeLinking
    99  		expect error
   100  	}{
   101  		{
   102  			evt: types.StakeLinking{
   103  				ID:     "someid1",
   104  				Type:   types.StakeLinkingTypeDeposited,
   105  				TS:     100,
   106  				Party:  testParty,
   107  				Amount: num.NewUint(10),
   108  			},
   109  			expect: nil,
   110  		},
   111  		{
   112  			evt: types.StakeLinking{
   113  				ID:     "someid2",
   114  				Type:   types.StakeLinkingTypeRemoved,
   115  				TS:     105,
   116  				Party:  testParty,
   117  				Amount: num.NewUint(1),
   118  			},
   119  			expect: nil,
   120  		},
   121  		{
   122  			evt: types.StakeLinking{
   123  				ID:     "someid3",
   124  				Type:   types.StakeLinkingTypeDeposited,
   125  				TS:     106,
   126  				Party:  testParty,
   127  				Amount: num.NewUint(3),
   128  			},
   129  			expect: nil,
   130  		},
   131  		{
   132  			evt: types.StakeLinking{
   133  				ID:     "someid4",
   134  				Type:   types.StakeLinkingTypeRemoved,
   135  				TS:     107,
   136  				Party:  testParty,
   137  				Amount: num.NewUint(4),
   138  			},
   139  			expect: nil,
   140  		},
   141  		{
   142  			evt: types.StakeLinking{
   143  				ID:     "someid5",
   144  				Type:   types.StakeLinkingTypeDeposited,
   145  				TS:     120,
   146  				Party:  testParty,
   147  				Amount: num.NewUint(5),
   148  			},
   149  			expect: nil,
   150  		},
   151  		{
   152  			evt: types.StakeLinking{
   153  				ID:     "someid6",
   154  				Type:   types.StakeLinkingTypeRemoved,
   155  				TS:     125,
   156  				Party:  testParty,
   157  				Amount: num.NewUint(6),
   158  			},
   159  			expect: nil,
   160  		},
   161  	}
   162  
   163  	acc.broker.EXPECT().Send(gomock.Any()).Times(1)
   164  
   165  	for _, c := range cases {
   166  		c := c
   167  		acc.AddEvent(context.Background(), &c.evt)
   168  	}
   169  
   170  	balance, err := acc.GetAvailableBalanceInRange(
   171  		testParty, time.Unix(0, 10), time.Unix(0, 20))
   172  	assert.NoError(t, err)
   173  	assert.Equal(t, num.NewUint(0), balance)
   174  
   175  	balance, err = acc.GetAvailableBalanceInRange(
   176  		testParty, time.Unix(0, 10), time.Unix(0, 110))
   177  	assert.NoError(t, err)
   178  	assert.Equal(t, num.NewUint(0), balance)
   179  
   180  	balance, err = acc.GetAvailableBalanceInRange(
   181  		testParty, time.Unix(0, 101), time.Unix(0, 109))
   182  	assert.NoError(t, err)
   183  	assert.Equal(t, num.NewUint(8), balance)
   184  
   185  	balance, err = acc.GetAvailableBalanceInRange(
   186  		testParty, time.Unix(0, 101), time.Unix(0, 111))
   187  	assert.NoError(t, err)
   188  	assert.Equal(t, num.NewUint(8), balance)
   189  
   190  	balance, err = acc.GetAvailableBalanceInRange(
   191  		testParty, time.Unix(0, 101), time.Unix(0, 121))
   192  	assert.NoError(t, err)
   193  	assert.Equal(t, num.NewUint(8), balance)
   194  
   195  	balance, err = acc.GetAvailableBalanceInRange(
   196  		testParty, time.Unix(0, 101), time.Unix(0, 126))
   197  	assert.NoError(t, err)
   198  	assert.Equal(t, num.NewUint(7), balance)
   199  }
   200  
   201  func testAccountingGetAvailableBalanceAt(t *testing.T) {
   202  	acc := getAccountingTest(t)
   203  	defer acc.ctrl.Finish()
   204  	cases := []struct {
   205  		evt    types.StakeLinking
   206  		expect error
   207  	}{
   208  		{
   209  			evt: types.StakeLinking{
   210  				ID:     "someid1",
   211  				Type:   types.StakeLinkingTypeDeposited,
   212  				TS:     100,
   213  				Party:  testParty,
   214  				Amount: num.NewUint(10),
   215  			},
   216  			expect: nil,
   217  		},
   218  		{
   219  			evt: types.StakeLinking{
   220  				ID:     "someid2",
   221  				Type:   types.StakeLinkingTypeRemoved,
   222  				TS:     110,
   223  				Party:  testParty,
   224  				Amount: num.NewUint(1),
   225  			},
   226  			expect: nil,
   227  		},
   228  		{
   229  			evt: types.StakeLinking{
   230  				ID:     "someid3",
   231  				Type:   types.StakeLinkingTypeDeposited,
   232  				TS:     120,
   233  				Party:  testParty,
   234  				Amount: num.NewUint(5),
   235  			},
   236  			expect: nil,
   237  		},
   238  	}
   239  
   240  	acc.broker.EXPECT().Send(gomock.Any()).Times(1)
   241  
   242  	for _, c := range cases {
   243  		c := c
   244  		acc.AddEvent(context.Background(), &c.evt)
   245  	}
   246  
   247  	balance, err := acc.GetAvailableBalanceAt(testParty, time.Unix(0, 10))
   248  	assert.NoError(t, err)
   249  	assert.Equal(t, num.NewUint(0), balance)
   250  	balance, err = acc.GetAvailableBalanceAt(testParty, time.Unix(0, 120))
   251  	assert.NoError(t, err)
   252  	assert.Equal(t, num.NewUint(14), balance)
   253  	balance, err = acc.GetAvailableBalanceAt(testParty, time.Unix(0, 115))
   254  	assert.NoError(t, err)
   255  	assert.Equal(t, num.NewUint(9), balance)
   256  }
   257  
   258  func testAccountingGenerateHash(t *testing.T) {
   259  	acc := getAccountingTest(t)
   260  	defer acc.ctrl.Finish()
   261  	cases := []struct {
   262  		evt    types.StakeLinking
   263  		expect error
   264  	}{
   265  		{
   266  			evt: types.StakeLinking{
   267  				ID:     "someid1",
   268  				Type:   types.StakeLinkingTypeDeposited,
   269  				TS:     100,
   270  				Party:  "party1",
   271  				Amount: num.NewUint(10),
   272  			},
   273  			expect: nil,
   274  		},
   275  		{
   276  			evt: types.StakeLinking{
   277  				ID:     "someid2",
   278  				Type:   types.StakeLinkingTypeRemoved,
   279  				TS:     110,
   280  				Party:  "party1",
   281  				Amount: num.NewUint(1),
   282  			},
   283  			expect: nil,
   284  		},
   285  		{
   286  			evt: types.StakeLinking{
   287  				ID:     "someid3",
   288  				Type:   types.StakeLinkingTypeDeposited,
   289  				TS:     120,
   290  				Party:  "party2",
   291  				Amount: num.NewUint(5),
   292  			},
   293  			expect: nil,
   294  		},
   295  		{
   296  			evt: types.StakeLinking{
   297  				ID:     "someid4",
   298  				Type:   types.StakeLinkingTypeDeposited,
   299  				TS:     120,
   300  				Party:  "party3",
   301  				Amount: num.NewUint(42),
   302  			},
   303  			expect: nil,
   304  		},
   305  	}
   306  
   307  	acc.broker.EXPECT().Send(gomock.Any()).Times(3)
   308  
   309  	for _, c := range cases {
   310  		c := c
   311  		acc.AddEvent(context.Background(), &c.evt)
   312  	}
   313  
   314  	require.Equal(t,
   315  		"ab5a48b34ac9f8c33a0441b6af04c84e2759086882b93aec972f4a709f93f8e9",
   316  		hex.EncodeToString(acc.Hash()),
   317  		"hash is not deterministic",
   318  	)
   319  }