code.vegaprotocol.io/vega@v0.79.0/core/banking/engine_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 banking_test
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"testing"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/core/assets"
    25  	"code.vegaprotocol.io/vega/core/assets/builtin"
    26  	"code.vegaprotocol.io/vega/core/banking"
    27  	"code.vegaprotocol.io/vega/core/banking/mocks"
    28  	bmocks "code.vegaprotocol.io/vega/core/broker/mocks"
    29  	"code.vegaprotocol.io/vega/core/types"
    30  	"code.vegaprotocol.io/vega/core/validators"
    31  	"code.vegaprotocol.io/vega/libs/num"
    32  	"code.vegaprotocol.io/vega/logging"
    33  
    34  	"github.com/golang/mock/gomock"
    35  	"github.com/stretchr/testify/assert"
    36  	"github.com/stretchr/testify/require"
    37  )
    38  
    39  var testAsset = assets.NewAsset(builtin.New("VGT", &types.AssetDetails{
    40  	Name:   "VEGA TOKEN",
    41  	Symbol: "VGT",
    42  }))
    43  
    44  type testEngine struct {
    45  	*banking.Engine
    46  	ctrl                  *gomock.Controller
    47  	witness               *fakeWitness
    48  	col                   *mocks.MockCollateral
    49  	assets                *mocks.MockAssets
    50  	tsvc                  *mocks.MockTimeService
    51  	top                   *mocks.MockTopology
    52  	broker                *bmocks.MockBroker
    53  	epoch                 *mocks.MockEpochService
    54  	primaryBridgeView     *mocks.MockERC20BridgeView
    55  	marketActivityTracker *mocks.MockMarketActivityTracker
    56  	ethSource             *mocks.MockEthereumEventSource
    57  	secondaryBridgeView   *mocks.MockERC20BridgeView
    58  	parties               *mocks.MockParties
    59  	stakeAccounting       *mocks.MockStakeAccounting
    60  }
    61  
    62  func getTestEngine(t *testing.T) *testEngine {
    63  	t.Helper()
    64  	ctrl := gomock.NewController(t)
    65  	witness := &fakeWitness{}
    66  	col := mocks.NewMockCollateral(ctrl)
    67  	assets := mocks.NewMockAssets(ctrl)
    68  	tsvc := mocks.NewMockTimeService(ctrl)
    69  	tsvc.EXPECT().GetTimeNow().DoAndReturn(
    70  		func() time.Time {
    71  			return time.Unix(10, 0)
    72  		}).AnyTimes()
    73  	notary := mocks.NewMockNotary(ctrl)
    74  	broker := bmocks.NewMockBroker(ctrl)
    75  	top := mocks.NewMockTopology(ctrl)
    76  	epoch := mocks.NewMockEpochService(ctrl)
    77  	stakeAccounting := mocks.NewMockStakeAccounting(ctrl)
    78  	primaryBridgeView := mocks.NewMockERC20BridgeView(ctrl)
    79  	secondaryBridgeView := mocks.NewMockERC20BridgeView(ctrl)
    80  	marketActivityTracker := mocks.NewMockMarketActivityTracker(ctrl)
    81  	marketActivityTracker.EXPECT().GameFinished(gomock.Any()).AnyTimes()
    82  	ethSource := mocks.NewMockEthereumEventSource(ctrl)
    83  
    84  	notary.EXPECT().OfferSignatures(gomock.Any(), gomock.Any()).AnyTimes()
    85  	epoch.EXPECT().NotifyOnEpoch(gomock.Any(), gomock.Any()).AnyTimes()
    86  	parties := mocks.NewMockParties(ctrl)
    87  	eng := banking.New(logging.NewTestLogger(), banking.NewDefaultConfig(), col, witness, tsvc, assets, notary, broker, top, marketActivityTracker, primaryBridgeView, secondaryBridgeView, ethSource, parties, stakeAccounting)
    88  
    89  	require.NoError(t, eng.OnMaxQuantumAmountUpdate(context.Background(), num.DecimalOne()))
    90  	eng.OnPrimaryEthChainIDUpdated("1", "hello")
    91  	eng.OnSecondaryEthChainIDUpdated("2", "hello2")
    92  
    93  	return &testEngine{
    94  		Engine:                eng,
    95  		ctrl:                  ctrl,
    96  		witness:               witness,
    97  		col:                   col,
    98  		assets:                assets,
    99  		tsvc:                  tsvc,
   100  		broker:                broker,
   101  		top:                   top,
   102  		epoch:                 epoch,
   103  		primaryBridgeView:     primaryBridgeView,
   104  		secondaryBridgeView:   secondaryBridgeView,
   105  		marketActivityTracker: marketActivityTracker,
   106  		ethSource:             ethSource,
   107  		parties:               parties,
   108  		stakeAccounting:       stakeAccounting,
   109  	}
   110  }
   111  
   112  func TestBanking(t *testing.T) {
   113  	t.Run("test deposit success", testDepositSuccess)
   114  	t.Run("test deposit success - no tx duplicate", testDepositSuccessNoTxDuplicate)
   115  	t.Run("test deposit failure", testDepositFailure)
   116  	t.Run("test deposit failure - not builtin", testDepositFailureNotBuiltin)
   117  	t.Run("test deposit error - start check fail", testDepositError)
   118  }
   119  
   120  func testDepositSuccess(t *testing.T) {
   121  	eng := getTestEngine(t)
   122  
   123  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   124  	eng.assets.EXPECT().Get(gomock.Any()).Times(1).Return(testAsset, nil)
   125  	eng.OnTick(context.Background(), time.Now())
   126  	bad := &types.BuiltinAssetDeposit{
   127  		VegaAssetID: "VGT",
   128  		PartyID:     "someparty",
   129  		Amount:      num.NewUint(42),
   130  	}
   131  
   132  	// call the deposit function
   133  	err := eng.DepositBuiltinAsset(context.Background(), bad, "depositid", 42)
   134  	assert.NoError(t, err)
   135  
   136  	// then we call the callback from the fake witness
   137  	eng.witness.r.Check(context.Background())
   138  	eng.witness.f(eng.witness.r, true)
   139  
   140  	// then we call time update, which should call the collateral to
   141  	// to do the deposit
   142  	eng.col.EXPECT().Deposit(gomock.Any(), bad.PartyID, bad.VegaAssetID, bad.Amount).Times(1).Return(&types.LedgerMovement{}, nil)
   143  
   144  	eng.OnTick(context.Background(), time.Now())
   145  }
   146  
   147  func testDepositSuccessNoTxDuplicate(t *testing.T) {
   148  	eng := getTestEngine(t)
   149  
   150  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   151  	eng.assets.EXPECT().Get(gomock.Any()).Times(2).Return(testAsset, nil)
   152  	eng.OnTick(context.Background(), time.Now())
   153  
   154  	bad := &types.BuiltinAssetDeposit{
   155  		VegaAssetID: "VGT",
   156  		PartyID:     "someparty",
   157  		Amount:      num.NewUint(42),
   158  	}
   159  
   160  	// call the deposit function
   161  	require.NoError(t, eng.DepositBuiltinAsset(context.Background(), bad, "depositid", 42))
   162  
   163  	// then we call the callback from the fake witness
   164  	eng.witness.r.Check(context.Background())
   165  	eng.witness.f(eng.witness.r, true)
   166  
   167  	// then we call time update, which should call the collateral to
   168  	// to do the deposit
   169  	eng.col.EXPECT().Deposit(gomock.Any(), bad.PartyID, bad.VegaAssetID, bad.Amount).Times(1).Return(&types.LedgerMovement{}, nil)
   170  
   171  	eng.OnTick(context.Background(), time.Now())
   172  
   173  	// call the deposit function
   174  	require.NoError(t, eng.DepositBuiltinAsset(context.Background(), bad, "depositid2", 43))
   175  
   176  	// then we call the callback from the fake witness
   177  	eng.witness.r.Check(context.Background())
   178  	eng.witness.f(eng.witness.r, true)
   179  
   180  	// then we call time update, which should call the collateral to
   181  	// to do the deposit
   182  	eng.col.EXPECT().Deposit(gomock.Any(), bad.PartyID, bad.VegaAssetID, bad.Amount).Times(1).Return(&types.LedgerMovement{}, nil)
   183  
   184  	eng.OnTick(context.Background(), time.Now())
   185  }
   186  
   187  func testDepositFailure(t *testing.T) {
   188  	eng := getTestEngine(t)
   189  
   190  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   191  	eng.assets.EXPECT().Get(gomock.Any()).Times(1).Return(testAsset, nil)
   192  	eng.OnTick(context.Background(), time.Now())
   193  	bad := &types.BuiltinAssetDeposit{
   194  		VegaAssetID: "VGT",
   195  		PartyID:     "someparty",
   196  		Amount:      num.NewUint(42),
   197  	}
   198  
   199  	// call the deposit function
   200  	err := eng.DepositBuiltinAsset(context.Background(), bad, "depositid", 42)
   201  	assert.NoError(t, err)
   202  
   203  	// then we call the callback from the fake witness
   204  	eng.witness.r.Check(context.Background())
   205  	eng.witness.f(eng.witness.r, false)
   206  
   207  	// then we call time update, expect collateral to never be called
   208  	eng.OnTick(context.Background(), time.Now())
   209  }
   210  
   211  func testDepositError(t *testing.T) {
   212  	eng := getTestEngine(t)
   213  
   214  	eng.broker.EXPECT().Send(gomock.Any()).Times(1)
   215  	eng.assets.EXPECT().Get(gomock.Any()).Times(1).Return(testAsset, nil)
   216  	eng.OnTick(context.Background(), time.Now())
   217  	bad := &types.BuiltinAssetDeposit{
   218  		VegaAssetID: "VGT",
   219  		PartyID:     "someparty",
   220  		Amount:      num.NewUint(42),
   221  	}
   222  
   223  	// set an error to be return by the fake witness
   224  	expectError := errors.New("bad bad bad")
   225  	eng.witness.err = expectError
   226  
   227  	// call the deposit function
   228  	err := eng.DepositBuiltinAsset(context.Background(), bad, "depositid", 42)
   229  	assert.EqualError(t, err, expectError.Error())
   230  }
   231  
   232  func testDepositFailureNotBuiltin(t *testing.T) {
   233  	eng := getTestEngine(t)
   234  
   235  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   236  	expectError := errors.New("bad bad bad")
   237  	eng.assets.EXPECT().Get(gomock.Any()).Times(1).Return(nil, expectError)
   238  	eng.OnTick(context.Background(), time.Now())
   239  	bad := &types.BuiltinAssetDeposit{
   240  		VegaAssetID: "VGT",
   241  		PartyID:     "someparty",
   242  		Amount:      num.NewUint(42),
   243  	}
   244  
   245  	// call the deposit function
   246  	err := eng.DepositBuiltinAsset(context.Background(), bad, "depositid", 42)
   247  	assert.EqualError(t, err, expectError.Error())
   248  }
   249  
   250  type fakeWitness struct {
   251  	r validators.Resource
   252  	f func(interface{}, bool)
   253  	t time.Time
   254  
   255  	err error
   256  }
   257  
   258  func (f *fakeWitness) StartCheck(r validators.Resource, fn func(interface{}, bool), t time.Time) error {
   259  	f.r = r
   260  	f.f = fn
   261  	f.t = t
   262  	return f.err
   263  }
   264  
   265  func (f *fakeWitness) RestoreResource(r validators.Resource, fn func(interface{}, bool)) error {
   266  	f.r = r
   267  	f.f = fn
   268  	return nil
   269  }