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 }