code.vegaprotocol.io/vega@v0.79.0/core/netparams/netparams_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 netparams_test 17 18 import ( 19 "context" 20 "encoding/json" 21 "testing" 22 "time" 23 24 bmocks "code.vegaprotocol.io/vega/core/broker/mocks" 25 "code.vegaprotocol.io/vega/core/netparams" 26 "code.vegaprotocol.io/vega/libs/num" 27 "code.vegaprotocol.io/vega/logging" 28 29 "github.com/golang/mock/gomock" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 type testNetParams struct { 35 *netparams.Store 36 ctrl *gomock.Controller 37 broker *bmocks.MockBroker 38 } 39 40 func getTestNetParams(t *testing.T) *testNetParams { 41 t.Helper() 42 ctrl := gomock.NewController(t) 43 broker := bmocks.NewMockBroker(ctrl) 44 store := netparams.New(logging.NewTestLogger(), netparams.NewDefaultConfig(), broker) 45 46 return &testNetParams{ 47 Store: store, 48 ctrl: ctrl, 49 broker: broker, 50 } 51 } 52 53 func TestNetParams(t *testing.T) { 54 t.Run("test validate - succes", testValidateSuccess) 55 t.Run("test validate - unknown key", testValidateUnknownKey) 56 t.Run("test validate - validation failed", testValidateValidationFailed) 57 t.Run("test update - success", testUpdateSuccess) 58 t.Run("test update - unknown key", testUpdateUnknownKey) 59 t.Run("test update - validation failed", testUpdateValidationFailed) 60 t.Run("test exists - success", testExistsSuccess) 61 t.Run("test exists - failure", testExistsFailure) 62 t.Run("get decimal", testGetDecimal) 63 t.Run("get duration", testGetDuration) 64 t.Run("dispatch after update", testDispatchAfterUpdate) 65 t.Run("register dispatch function - failure", testRegisterDispatchFunctionFailure) 66 } 67 68 func TestCheckpoint(t *testing.T) { 69 t.Run("test get snapshot not empty", testNonEmptyCheckpoint) 70 t.Run("test get snapshot not empty with overwrite", testNonEmptyCheckpointWithOverWrite) 71 t.Run("test get snapshot invalid", testInvalidCheckpoint) 72 t.Run("test notification is sent after checkpoint load", testCheckpointNotificationsDelivered) 73 } 74 75 func testRegisterDispatchFunctionFailure(t *testing.T) { 76 netp := getTestNetParams(t) 77 defer netp.ctrl.Finish() 78 79 err := netp.Watch( 80 netparams.WatchParam{ 81 Param: netparams.GovernanceProposalAssetMaxClose, 82 Watcher: func(s string) error { return nil }, 83 }, 84 ) 85 86 assert.EqualError(t, err, "governance.proposal.asset.maxClose: invalid type, expected func(context.Context, time.Duration) error") 87 } 88 89 func testDispatchAfterUpdate(t *testing.T) { 90 netp := getTestNetParams(t) 91 defer netp.ctrl.Finish() 92 93 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 94 newDuration := "10s" 95 var wasCalled bool 96 f := func(_ context.Context, d time.Duration) error { 97 assert.Equal(t, d, 10*time.Second) 98 wasCalled = true 99 return nil 100 } 101 102 err := netp.Watch( 103 netparams.WatchParam{ 104 Param: netparams.GovernanceProposalAssetMaxClose, 105 Watcher: f, 106 }, 107 ) 108 109 assert.NoError(t, err) 110 111 err = netp.Update(context.Background(), netparams.GovernanceProposalAssetMaxClose, newDuration) 112 assert.NoError(t, err) 113 114 netp.DispatchChanges(context.Background()) 115 assert.True(t, wasCalled) 116 } 117 118 func testValidateSuccess(t *testing.T) { 119 netp := getTestNetParams(t) 120 defer netp.ctrl.Finish() 121 122 err := netp.Validate(netparams.GovernanceProposalMarketMinClose, "10h") 123 assert.NoError(t, err) 124 } 125 126 func testValidateUnknownKey(t *testing.T) { 127 netp := getTestNetParams(t) 128 defer netp.ctrl.Finish() 129 130 err := netp.Validate("not.a.valid.key", "10h") 131 assert.EqualError(t, err, netparams.ErrUnknownKey.Error()) 132 } 133 134 func testValidateValidationFailed(t *testing.T) { 135 netp := getTestNetParams(t) 136 defer netp.ctrl.Finish() 137 138 err := netp.Validate(netparams.GovernanceProposalMarketMinClose, "asdasdasd") 139 assert.Error(t, err) 140 assert.Contains(t, err.Error(), "time: invalid duration") 141 } 142 143 func testUpdateSuccess(t *testing.T) { 144 netp := getTestNetParams(t) 145 defer netp.ctrl.Finish() 146 147 // get the original default value 148 ov, err := netp.Get(netparams.GovernanceProposalMarketMinClose) 149 assert.NoError(t, err) 150 assert.NotEmpty(t, ov) 151 assert.NotEqual(t, ov, "10h") 152 153 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 154 155 err = netp.Update( 156 context.Background(), netparams.GovernanceProposalMarketMinClose, "10h") 157 assert.NoError(t, err) 158 159 nv, err := netp.Get(netparams.GovernanceProposalMarketMinClose) 160 assert.NoError(t, err) 161 assert.NotEmpty(t, nv) 162 assert.NotEqual(t, nv, ov) 163 assert.Equal(t, nv, "10h") 164 } 165 166 func testUpdateUnknownKey(t *testing.T) { 167 netp := getTestNetParams(t) 168 defer netp.ctrl.Finish() 169 170 err := netp.Update(context.Background(), "not.a.valid.key", "10h") 171 assert.EqualError(t, err, netparams.ErrUnknownKey.Error()) 172 } 173 174 func testUpdateValidationFailed(t *testing.T) { 175 netp := getTestNetParams(t) 176 defer netp.ctrl.Finish() 177 178 err := netp.Update( 179 context.Background(), netparams.GovernanceProposalMarketMinClose, "asdadasd") 180 assert.Error(t, err) 181 assert.Contains(t, err.Error(), "time: invalid duration") 182 } 183 184 func testExistsSuccess(t *testing.T) { 185 netp := getTestNetParams(t) 186 defer netp.ctrl.Finish() 187 188 ok := netp.Exists(netparams.GovernanceProposalMarketMinClose) 189 assert.True(t, ok) 190 } 191 192 func testExistsFailure(t *testing.T) { 193 netp := getTestNetParams(t) 194 defer netp.ctrl.Finish() 195 196 ok := netp.Exists("not.valid") 197 assert.False(t, ok) 198 } 199 200 func testGetDecimal(t *testing.T) { 201 netp := getTestNetParams(t) 202 defer netp.ctrl.Finish() 203 204 _, err := netp.GetDecimal(netparams.GovernanceProposalUpdateNetParamRequiredMajority) 205 assert.NoError(t, err) 206 _, err = netp.GetInt(netparams.GovernanceProposalAssetMaxClose) 207 assert.EqualError(t, err, "not an int value") 208 } 209 210 func testGetDuration(t *testing.T) { 211 netp := getTestNetParams(t) 212 defer netp.ctrl.Finish() 213 214 _, err := netp.GetDuration(netparams.GovernanceProposalAssetMaxClose) 215 assert.NoError(t, err) 216 _, err = netp.GetDuration(netparams.GovernanceProposalAssetMinProposerBalance) 217 assert.EqualError(t, err, "not a time.Duration value") 218 } 219 220 func testNonEmptyCheckpoint(t *testing.T) { 221 netp := getTestNetParams(t) 222 defer netp.ctrl.Finish() 223 ctx := context.Background() 224 225 // get the original default value 226 ov, err := netp.Get(netparams.GovernanceProposalMarketMinClose) 227 assert.NoError(t, err) 228 assert.NotEmpty(t, ov) 229 assert.NotEqual(t, ov, "10h") 230 231 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 232 233 err = netp.Update(ctx, netparams.GovernanceProposalMarketMinClose, "10h") 234 assert.NoError(t, err) 235 236 nv, err := netp.Get(netparams.GovernanceProposalMarketMinClose) 237 assert.NoError(t, err) 238 assert.NotEmpty(t, nv) 239 assert.NotEqual(t, nv, ov) 240 assert.Equal(t, nv, "10h") 241 242 data, err := netp.Checkpoint() 243 require.NoError(t, err) 244 require.NotEmpty(t, data) 245 246 // now try and load the checkpoint 247 netp2 := getTestNetParams(t) 248 defer netp2.ctrl.Finish() 249 250 // ensure the state != checkpoint we took 251 ov2, err := netp2.Get(netparams.GovernanceProposalMarketMinClose) 252 assert.NoError(t, err) 253 assert.NotEmpty(t, ov2) 254 assert.NotEqual(t, ov2, "10h") 255 require.Equal(t, ov, ov2) 256 257 netp2.broker.EXPECT().SendBatch(gomock.Any()).Times(1) 258 require.NoError(t, netp2.Load(ctx, data)) 259 260 nv2, err := netp2.Get(netparams.GovernanceProposalMarketMinClose) 261 assert.NoError(t, err) 262 assert.NotEmpty(t, nv2) 263 assert.NotEqual(t, nv2, ov) 264 assert.Equal(t, nv, nv2) 265 266 // make sure that, once restored, the same checkpoint data is restored 267 data2, err := netp2.Checkpoint() 268 require.NoError(t, err) 269 require.EqualValues(t, data, data2) 270 } 271 272 func testInvalidCheckpoint(t *testing.T) { 273 netp := getTestNetParams(t) 274 defer netp.ctrl.Finish() 275 ctx := context.Background() 276 277 data, err := netp.Checkpoint() 278 require.NoError(t, err) 279 require.NotEmpty(t, data) 280 281 data = append(data, []byte("foobar")...) // corrupt the data 282 require.Error(t, netp.Load(ctx, data)) 283 } 284 285 func testCheckpointNotificationsDelivered(t *testing.T) { 286 netp := getTestNetParams(t) 287 defer netp.ctrl.Finish() 288 ctx := context.Background() 289 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 290 291 counter := 0 292 countNotificationsFunc := func(_ context.Context, minAmount num.Decimal) error { 293 counter++ 294 return nil 295 } 296 297 netp.Watch( 298 netparams.WatchParam{ 299 Param: netparams.DelegationMinAmount, 300 Watcher: countNotificationsFunc, 301 }, 302 ) 303 304 err := netp.Update(ctx, netparams.DelegationMinAmount, "2.0") 305 assert.NoError(t, err) 306 307 netp.OnTick(ctx, time.Now()) 308 require.Equal(t, 1, counter) 309 310 cp, err := netp.Checkpoint() 311 require.NoError(t, err) 312 313 loadNp := getTestNetParams(t) 314 defer loadNp.ctrl.Finish() 315 loadNp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 316 loadNp.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes() 317 318 var loadMinAmount num.Decimal 319 loadCountNotificationsFunc := func(_ context.Context, minAmount num.Decimal) error { 320 loadMinAmount = minAmount 321 return nil 322 } 323 loadNp.Watch( 324 netparams.WatchParam{ 325 Param: netparams.DelegationMinAmount, 326 Watcher: loadCountNotificationsFunc, 327 }, 328 ) 329 loadNp.Load(ctx, cp) 330 loadNp.OnTick(ctx, time.Now()) 331 require.Equal(t, "2", loadMinAmount.String()) 332 } 333 334 func testNonEmptyCheckpointWithOverWrite(t *testing.T) { 335 netp := getTestNetParams(t) 336 defer netp.ctrl.Finish() 337 ctx := context.Background() 338 339 // get the original default value 340 ov, err := netp.Get(netparams.GovernanceProposalMarketMinClose) 341 assert.NoError(t, err) 342 assert.NotEmpty(t, ov) 343 assert.NotEqual(t, ov, "10h") 344 345 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 346 347 err = netp.Update(ctx, netparams.GovernanceProposalMarketMinClose, "10h") 348 assert.NoError(t, err) 349 350 nv, err := netp.Get(netparams.GovernanceProposalMarketMinClose) 351 assert.NoError(t, err) 352 assert.NotEmpty(t, nv) 353 assert.NotEqual(t, nv, ov) 354 assert.Equal(t, nv, "10h") 355 356 data, err := netp.Checkpoint() 357 require.NoError(t, err) 358 require.NotEmpty(t, data) 359 360 // now try and load the checkpoint 361 netp2 := getTestNetParams(t) 362 defer netp2.ctrl.Finish() 363 netp2.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes() 364 netp2.broker.EXPECT().Send(gomock.Any()).AnyTimes() 365 366 genesis := map[string]interface{}{ 367 "network_parameters": map[string]string{ 368 "market.liquidity.successorLaunchWindowLength": "1h", 369 }, 370 "network_parameters_checkpoint_overwrite": []string{"market.liquidity.successorLaunchWindowLength"}, 371 } 372 373 buf, err := json.Marshal(genesis) 374 assert.NoError(t, err) 375 376 assert.NoError(t, netp2.UponGenesis(context.Background(), buf)) 377 378 // ensure the state != checkpoint we took 379 ov2, err := netp2.Get(netparams.GovernanceProposalMarketMinClose) 380 assert.NoError(t, err) 381 assert.NotEmpty(t, ov2) 382 assert.NotEqual(t, ov2, "10h") 383 require.Equal(t, ov, ov2) 384 385 require.NoError(t, netp2.Load(ctx, data)) 386 387 nv2, err := netp2.Get(netparams.GovernanceProposalMarketMinClose) 388 assert.NoError(t, err) 389 assert.NotEmpty(t, nv2) 390 assert.NotEqual(t, nv2, ov) 391 assert.Equal(t, nv, nv2) 392 393 // make sure that, once restored, the same checkpoint data is restored 394 _, err = netp2.Checkpoint() 395 require.NoError(t, err) 396 } 397 398 func TestCrossNetParamUpdates(t *testing.T) { 399 netp := getTestNetParams(t) 400 defer netp.ctrl.Finish() 401 402 // min and max durations are defined such that min must be less than max, so lets first verify that the constraint holds 403 min, err := netp.GetDuration(netparams.MarketAuctionMinimumDuration) 404 require.NoError(t, err) 405 require.Equal(t, time.Minute*30, min) 406 407 max, err := netp.GetDuration(netparams.MarketAuctionMaximumDuration) 408 require.NoError(t, err) 409 require.Equal(t, time.Hour*168, max) 410 411 // now lets try to update max to a valid value (1s) with respect to its own validation rules but would invalidate the invariant of max > min 412 err = netp.Validate(netparams.MarketAuctionMaximumDuration, "1s") 413 require.Equal(t, "unable to validate market.auction.maximumDuration: expect > 30m0s (market.auction.minimumDuration) got 1s", err.Error()) 414 415 // now lets change the maximum to be 12h so that we can cross it with the minimum 416 err = netp.Validate(netparams.MarketAuctionMaximumDuration, "12h") 417 require.NoError(t, err) 418 419 netp.broker.EXPECT().Send(gomock.Any()).Times(1) 420 netp.Update(context.Background(), netparams.MarketAuctionMaximumDuration, "12h") 421 422 // now lets try to update min to a valid value (13h) with respect to its own validation rules but would invalidate the invariant of max > min 423 err = netp.Validate(netparams.MarketAuctionMinimumDuration, "13h") 424 require.Equal(t, "unable to validate market.auction.minimumDuration: expect < 12h0m0s (market.auction.maximumDuration) got 13h0m0s", err.Error()) 425 } 426 427 func TestCrossNetParamUpdatesInGenesis(t *testing.T) { 428 netp := getTestNetParams(t) 429 defer netp.ctrl.Finish() 430 431 genesis1 := map[string]interface{}{ 432 "network_parameters": map[string]string{ 433 "network.validators.tendermint.number": "5", 434 "network.validators.multisig.numberOfSigners": "5", 435 }, 436 "network_parameters_checkpoint_overwrite": []string{}, 437 } 438 439 netp.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes() 440 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 441 buf, err := json.Marshal(genesis1) 442 require.NoError(t, err) 443 require.NoError(t, netp.UponGenesis(context.Background(), buf)) 444 445 genesis2 := map[string]interface{}{ 446 "network_parameters": map[string]string{ 447 "network.validators.multisig.numberOfSigners": "5", 448 "network.validators.tendermint.number": "5", 449 }, 450 "network_parameters_checkpoint_overwrite": []string{}, 451 } 452 453 netp.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes() 454 netp.broker.EXPECT().Send(gomock.Any()).AnyTimes() 455 buf, err = json.Marshal(genesis2) 456 require.NoError(t, err) 457 require.NoError(t, netp.UponGenesis(context.Background(), buf)) 458 } 459 460 func TestDefaultStateHidesDeprecated(t *testing.T) { 461 st := netparams.DefaultGenesisState() 462 463 for v := range st { 464 _, ok := netparams.Deprecated[v] 465 assert.False(t, ok) 466 } 467 }