code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/node_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 sqlstore_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/datanode/entities" 24 "code.vegaprotocol.io/vega/datanode/sqlstore" 25 vegapb "code.vegaprotocol.io/vega/protos/vega" 26 27 "github.com/georgysavva/scany/pgxscan" 28 "github.com/shopspring/decimal" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func addTestNode(t *testing.T, ctx context.Context, ps *sqlstore.Node, block entities.Block, id string) entities.Node { 34 t.Helper() 35 node := entities.Node{ 36 ID: entities.NodeID(id), 37 PubKey: entities.VegaPublicKey(GenerateID()), 38 TmPubKey: entities.TendermintPublicKey(generateTendermintPublicKey()), 39 EthereumAddress: entities.EthereumAddress(generateEthereumAddress()), 40 VegaTime: block.VegaTime, 41 Status: entities.NodeStatusNonValidator, 42 TxHash: generateTxHash(), 43 } 44 45 err := ps.UpsertNode(ctx, &node) 46 require.NoError(t, err) 47 return node 48 } 49 50 func addNodeAnnounced(t *testing.T, ctx context.Context, ps *sqlstore.Node, nodeID entities.NodeID, added bool, epochSeq uint64, vegatime time.Time) { 51 t.Helper() 52 aux := entities.ValidatorUpdateAux{ 53 Added: added, 54 EpochSeq: epochSeq, 55 } 56 err := ps.AddNodeAnnouncedEvent(ctx, nodeID.String(), vegatime, &aux) 57 require.NoError(t, err) 58 } 59 60 func addRankingScore(t *testing.T, ctx context.Context, ps *sqlstore.Node, node entities.Node, r entities.RankingScore) { 61 t.Helper() 62 63 aux := entities.RankingScoreAux{ 64 NodeID: node.ID, 65 EpochSeq: r.EpochSeq, 66 } 67 68 err := ps.UpsertRanking(ctx, &r, &aux) 69 require.NoError(t, err) 70 } 71 72 func TestUpdateNodePubKey(t *testing.T) { 73 ctx := tempTransaction(t) 74 75 bs := sqlstore.NewBlocks(connectionSource) 76 ns := sqlstore.NewNode(connectionSource) 77 block := addTestBlock(t, ctx, bs) 78 79 now := time.Now() 80 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 81 addNodeAnnounced(t, ctx, ns, node1.ID, true, 0, now) 82 83 kr := entities.KeyRotation{ 84 NodeID: node1.ID, 85 OldPubKey: node1.PubKey, 86 NewPubKey: entities.VegaPublicKey(GenerateID()), 87 VegaTime: block.VegaTime, 88 } 89 90 ns.UpdatePublicKey(ctx, &kr) 91 92 fetched, err := ns.GetNodeByID(ctx, node1.ID.String(), 1) 93 assert.NoError(t, err) 94 assert.Equal(t, fetched.PubKey, kr.NewPubKey) 95 } 96 97 func TestGetNodes(t *testing.T) { 98 ctx := tempTransaction(t) 99 100 bs := sqlstore.NewBlocks(connectionSource) 101 ns := sqlstore.NewNode(connectionSource) 102 block := addTestBlock(t, ctx, bs) 103 104 now := time.Now() 105 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 106 addNodeAnnounced(t, ctx, ns, node1.ID, true, 0, now) 107 addNodeAnnounced(t, ctx, ns, node1.ID, false, 7, now) 108 addRankingScore(t, ctx, ns, node1, 109 entities.RankingScore{ 110 StakeScore: decimal.NewFromFloat(0.5), 111 PerformanceScore: decimal.NewFromFloat(0.25), 112 PreviousStatus: entities.ValidatorNodeStatusErsatz, 113 Status: entities.ValidatorNodeStatusTendermint, 114 EpochSeq: 3, 115 VegaTime: block.VegaTime, 116 }) 117 118 // get all nodes 119 found, _, err := ns.GetNodes(ctx, 3, entities.CursorPagination{}) 120 require.NoError(t, err) 121 require.Len(t, found, 1) 122 123 // get all nodes 124 found, _, err = ns.GetNodes(ctx, 7, entities.CursorPagination{}) 125 require.NoError(t, err) 126 require.Len(t, found, 0) 127 128 // get single node in epoch where it had a ranking 129 node, err := ns.GetNodeByID(ctx, node1.ID.String(), 3) 130 require.NoError(t, err) 131 require.NotNil(t, node) 132 require.NotNil(t, node.RankingScore) 133 134 node, err = ns.GetNodeByID(ctx, "DEADBEEF", 3) 135 require.Error(t, err) 136 137 // check the value can be changed, since this happens during a checkpoint restore 138 // we were need to remove genesis validators if they aren't in the checkpoint 139 addNodeAnnounced(t, ctx, ns, node1.ID, true, 7, now) 140 // get all nodes 141 found, _, err = ns.GetNodes(ctx, 7, entities.CursorPagination{}) 142 require.NoError(t, err) 143 require.Len(t, found, 1) 144 } 145 146 func TestNodeGetByTxHash(t *testing.T) { 147 ctx := tempTransaction(t) 148 149 bs := sqlstore.NewBlocks(connectionSource) 150 ns := sqlstore.NewNode(connectionSource) 151 block := addTestBlock(t, ctx, bs) 152 153 now := time.Now() 154 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 155 node2 := addTestNode(t, ctx, ns, block, GenerateID()) 156 addNodeAnnounced(t, ctx, ns, node1.ID, true, 0, now) 157 addNodeAnnounced(t, ctx, ns, node2.ID, false, 7, now) 158 addNodeAnnounced(t, ctx, ns, node2.ID, false, 9, now) 159 160 found, err := ns.GetByTxHash(ctx, node1.TxHash) 161 require.NoError(t, err) 162 require.Len(t, found, 1) 163 require.Equal(t, node1.ID, found[0].ID) 164 165 found, err = ns.GetByTxHash(ctx, node2.TxHash) 166 require.NoError(t, err) 167 require.Len(t, found, 1) 168 require.Equal(t, node2.ID, found[0].ID) 169 } 170 171 func TestGetNodesJoiningAndLeaving(t *testing.T) { 172 ctx := tempTransaction(t) 173 174 bs := sqlstore.NewBlocks(connectionSource) 175 ns := sqlstore.NewNode(connectionSource) 176 block := addTestBlock(t, ctx, bs) 177 178 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 179 node2 := addTestNode(t, ctx, ns, block, GenerateID()) 180 181 // The node1 will exist int the epochs [2,3] and [6,7] 182 exists := map[int]bool{2: true, 3: true, 6: true, 7: true} 183 addNodeAnnounced(t, ctx, ns, node1.ID, true, 2, time.Now()) 184 addNodeAnnounced(t, ctx, ns, node1.ID, false, 4, time.Now()) 185 addNodeAnnounced(t, ctx, ns, node1.ID, true, 6, time.Now()) 186 addNodeAnnounced(t, ctx, ns, node1.ID, false, 8, time.Now()) 187 188 // node2 will always exist 189 addNodeAnnounced(t, ctx, ns, node2.ID, true, 0, time.Now()) 190 191 nodeID1 := node1.ID.String() 192 nodeID2 := node2.ID.String() 193 194 assertNodeExistence(ctx, t, ns, nodeID1, 1, false) 195 assertNodeExistence(ctx, t, ns, nodeID2, 1, true) 196 for i := 1; i < 10; i++ { 197 assertNodeExistence(ctx, t, ns, nodeID1, uint64(i), exists[i]) 198 assertNodeExistence(ctx, t, ns, nodeID2, uint64(i), true) 199 } 200 } 201 202 func TestGetNodeData(t *testing.T) { 203 ctx := tempTransaction(t) 204 205 bs := sqlstore.NewBlocks(connectionSource) 206 ns := sqlstore.NewNode(connectionSource) 207 es := sqlstore.NewEpochs(connectionSource) 208 ds := sqlstore.NewDelegations(connectionSource) 209 ps := sqlstore.NewParties(connectionSource) 210 211 block := addTestBlock(t, ctx, bs) 212 party1 := addTestParty(t, ctx, ps, block) 213 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 214 node2 := addTestNode(t, ctx, ns, block, GenerateID()) 215 216 addTestDelegation(t, ctx, ds, party1, node1, 3, block, 0) 217 addTestDelegation(t, ctx, ds, party1, node1, 4, block, 1) 218 addTestDelegation(t, ctx, ds, party1, node2, 3, block, 2) 219 addTestDelegation(t, ctx, ds, party1, node2, 4, block, 3) 220 221 // node1 goes from pending -> ersatz -> tendermint 222 // then gets demoted straight to pending with a zero perf score 223 addRankingScore(t, ctx, ns, node1, 224 entities.RankingScore{ 225 StakeScore: decimal.NewFromFloat(0.5), 226 PerformanceScore: decimal.NewFromFloat(0.25), 227 PreviousStatus: entities.ValidatorNodeStatusPending, 228 Status: entities.ValidatorNodeStatusErsatz, 229 EpochSeq: 2, 230 VegaTime: block.VegaTime, 231 }) 232 addRankingScore(t, ctx, ns, node1, 233 entities.RankingScore{ 234 StakeScore: decimal.NewFromFloat(0.5), 235 PerformanceScore: decimal.NewFromFloat(0.25), 236 PreviousStatus: entities.ValidatorNodeStatusErsatz, 237 Status: entities.ValidatorNodeStatusTendermint, 238 EpochSeq: 3, 239 VegaTime: block.VegaTime, 240 }) 241 addRankingScore(t, ctx, ns, node1, 242 entities.RankingScore{ 243 StakeScore: decimal.NewFromFloat(0.5), 244 PerformanceScore: decimal.Zero, 245 PreviousStatus: entities.ValidatorNodeStatusTendermint, 246 Status: entities.ValidatorNodeStatusPending, 247 EpochSeq: 4, 248 VegaTime: block.VegaTime, 249 }) 250 251 // node 2 is always a happy tendermint node 252 for i := 0; i < 6; i++ { 253 addRankingScore(t, ctx, ns, node2, entities.RankingScore{ 254 StakeScore: decimal.NewFromFloat(0.5), 255 PerformanceScore: decimal.NewFromFloat(0.25), 256 PreviousStatus: entities.ValidatorNodeStatusTendermint, 257 Status: entities.ValidatorNodeStatusTendermint, 258 EpochSeq: uint64(i), 259 VegaTime: block.VegaTime, 260 }) 261 } 262 263 // The node1 will exist int the epochs [2,3,4] 264 addNodeAnnounced(t, ctx, ns, node1.ID, true, 2, time.Now()) 265 addNodeAnnounced(t, ctx, ns, node1.ID, false, 5, time.Now()) 266 267 // node2 will always exist 268 addNodeAnnounced(t, ctx, ns, node2.ID, true, 0, time.Now()) 269 270 // move to epoch 2 both nodes should exist 271 now := time.Unix(2000, 4) 272 addTestEpoch(t, ctx, es, 2, now, now, &now, block) 273 nodeData, err := ns.GetNodeData(ctx, 2) 274 require.NoError(t, err) 275 require.Equal(t, uint32(2), nodeData.TotalNodes) 276 require.Equal(t, entities.NodeSet{ 277 Total: 1, 278 }, nodeData.TendermintNodes) 279 require.Equal(t, entities.NodeSet{ 280 Total: 1, 281 Promoted: []string{node1.ID.String()}, 282 }, nodeData.ErsatzNodes) 283 require.Equal(t, entities.NodeSet{}, nodeData.PendingNodes) 284 285 // move to epoch 3 and check promotions 286 addTestEpoch(t, ctx, es, 3, now, now, &now, block) 287 nodeData, err = ns.GetNodeData(ctx, 3) 288 require.NoError(t, err) 289 require.Equal(t, uint32(2), nodeData.TotalNodes) 290 require.Equal(t, entities.NodeSet{ 291 Total: 2, 292 Promoted: []string{node1.ID.String()}, 293 }, nodeData.TendermintNodes) 294 require.Equal(t, entities.NodeSet{}, nodeData.ErsatzNodes) 295 require.Equal(t, entities.NodeSet{}, nodeData.PendingNodes) 296 297 // move to epoch 4 and check demotions 298 now = now.Add(time.Hour) 299 addTestEpoch(t, ctx, es, 4, now, now, &now, block) 300 nodeData, err = ns.GetNodeData(ctx, 4) 301 require.NoError(t, err) 302 require.Equal(t, uint32(2), nodeData.TotalNodes) 303 require.Equal(t, uint32(1), nodeData.InactiveNodes) 304 require.Equal(t, entities.NodeSet{ 305 Total: 1, 306 }, nodeData.TendermintNodes) 307 require.Equal(t, entities.NodeSet{}, nodeData.ErsatzNodes) 308 require.Equal(t, entities.NodeSet{ 309 Total: 1, 310 Inactive: 1, 311 Demoted: []string{node1.ID.String()}, 312 }, nodeData.PendingNodes) 313 314 // move to epoch 5 just have one tendermint node 315 now = now.Add(time.Hour) 316 addTestEpoch(t, ctx, es, 5, now, now, &now, block) 317 nodeData, err = ns.GetNodeData(ctx, 5) 318 require.NoError(t, err) 319 require.Equal(t, uint32(1), nodeData.TotalNodes) 320 require.Equal(t, entities.NodeSet{ 321 Total: 1, 322 }, nodeData.TendermintNodes) 323 require.Equal(t, entities.NodeSet{}, nodeData.ErsatzNodes) 324 require.Equal(t, entities.NodeSet{}, nodeData.PendingNodes) 325 } 326 327 func assertNodeExistence(ctx context.Context, t *testing.T, ns *sqlstore.Node, nodeID string, epoch uint64, exists bool) { 328 t.Helper() 329 nodes, _, err := ns.GetNodes(ctx, epoch, entities.CursorPagination{}) 330 require.NoError(t, err) 331 node, err := ns.GetNodeByID(ctx, nodeID, epoch) 332 333 found := false 334 for _, n := range nodes { 335 if n.ID.String() == nodeID { 336 found = true 337 break 338 } 339 } 340 341 if !exists { 342 require.ErrorIs(t, err, entities.ErrNotFound) 343 require.False(t, found) 344 return 345 } 346 347 require.NoError(t, err) 348 require.True(t, found) 349 require.Equal(t, node.ID.String(), nodeID) 350 } 351 352 func TestNodePagination(t *testing.T) { 353 t.Run("Should return all nodes if no pagination is specified", testNodePaginationNoPagination) 354 t.Run("Should return first page of results if first is provided", testNodePaginationFirst) 355 t.Run("Should return last page of results if last is provided", testNodePaginationLast) 356 t.Run("Should return requested page of results if first and after is provided", testNodePaginationFirstAfter) 357 t.Run("Should return requested page of results if last and before is provided", testNodePaginationLastBefore) 358 } 359 360 func addPaginationTestNodes(t *testing.T, ctx context.Context, ns *sqlstore.Node) (nodes []entities.Node) { 361 t.Helper() 362 blockTime := time.Now().Add(-time.Hour) 363 bs := sqlstore.NewBlocks(connectionSource) 364 365 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef01")) 366 blockTime = blockTime.Add(time.Minute) 367 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef02")) 368 blockTime = blockTime.Add(time.Minute) 369 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef03")) 370 blockTime = blockTime.Add(time.Minute) 371 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef04")) 372 blockTime = blockTime.Add(time.Minute) 373 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef05")) 374 blockTime = blockTime.Add(time.Minute) 375 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef06")) 376 blockTime = blockTime.Add(time.Minute) 377 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef07")) 378 blockTime = blockTime.Add(time.Minute) 379 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef08")) 380 blockTime = blockTime.Add(time.Minute) 381 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef09")) 382 blockTime = blockTime.Add(time.Minute) 383 nodes = append(nodes, addTestNode(t, ctx, ns, addTestBlockForTime(t, ctx, bs, blockTime), "deadbeef10")) 384 addNodeAnnounced(t, ctx, ns, nodes[0].ID, true, 1, nodes[0].VegaTime) 385 addNodeAnnounced(t, ctx, ns, nodes[1].ID, true, 1, nodes[1].VegaTime) 386 addNodeAnnounced(t, ctx, ns, nodes[2].ID, true, 1, nodes[2].VegaTime) 387 addNodeAnnounced(t, ctx, ns, nodes[3].ID, true, 1, nodes[3].VegaTime) 388 addNodeAnnounced(t, ctx, ns, nodes[4].ID, true, 1, nodes[4].VegaTime) 389 addNodeAnnounced(t, ctx, ns, nodes[5].ID, true, 1, nodes[5].VegaTime) 390 addNodeAnnounced(t, ctx, ns, nodes[6].ID, true, 1, nodes[6].VegaTime) 391 addNodeAnnounced(t, ctx, ns, nodes[7].ID, true, 1, nodes[7].VegaTime) 392 addNodeAnnounced(t, ctx, ns, nodes[8].ID, true, 1, nodes[8].VegaTime) 393 addNodeAnnounced(t, ctx, ns, nodes[9].ID, true, 1, nodes[9].VegaTime) 394 395 return nodes 396 } 397 398 func testNodePaginationNoPagination(t *testing.T) { 399 ctx := tempTransaction(t) 400 401 ns := sqlstore.NewNode(connectionSource) 402 nodes := addPaginationTestNodes(t, ctx, ns) 403 404 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false) 405 require.NoError(t, err) 406 407 got, pageInfo, err := ns.GetNodes(ctx, 1, pagination) 408 require.NoError(t, err) 409 assert.Len(t, got, len(nodes)) 410 assert.Equal(t, nodes[0].ID, got[0].ID) 411 assert.Equal(t, nodes[1].ID, got[1].ID) 412 assert.Equal(t, nodes[2].ID, got[2].ID) 413 assert.Equal(t, nodes[3].ID, got[3].ID) 414 assert.Equal(t, nodes[4].ID, got[4].ID) 415 assert.Equal(t, nodes[5].ID, got[5].ID) 416 assert.Equal(t, nodes[6].ID, got[6].ID) 417 assert.Equal(t, nodes[7].ID, got[7].ID) 418 assert.Equal(t, nodes[8].ID, got[8].ID) 419 assert.Equal(t, nodes[9].ID, got[9].ID) 420 assert.Equal(t, entities.PageInfo{ 421 HasNextPage: false, 422 HasPreviousPage: false, 423 StartCursor: nodes[0].Cursor().Encode(), 424 EndCursor: nodes[9].Cursor().Encode(), 425 }, pageInfo) 426 } 427 428 func testNodePaginationFirst(t *testing.T) { 429 ctx := tempTransaction(t) 430 431 ns := sqlstore.NewNode(connectionSource) 432 nodes := addPaginationTestNodes(t, ctx, ns) 433 first := int32(3) 434 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 435 require.NoError(t, err) 436 437 got, pageInfo, err := ns.GetNodes(ctx, 1, pagination) 438 require.NoError(t, err) 439 assert.Len(t, got, 3) 440 assert.Equal(t, nodes[0].ID, got[0].ID) 441 assert.Equal(t, nodes[1].ID, got[1].ID) 442 assert.Equal(t, nodes[2].ID, got[2].ID) 443 assert.Equal(t, entities.PageInfo{ 444 HasNextPage: true, 445 HasPreviousPage: false, 446 StartCursor: nodes[0].Cursor().Encode(), 447 EndCursor: nodes[2].Cursor().Encode(), 448 }, pageInfo) 449 } 450 451 func testNodePaginationLast(t *testing.T) { 452 ctx := tempTransaction(t) 453 454 ns := sqlstore.NewNode(connectionSource) 455 nodes := addPaginationTestNodes(t, ctx, ns) 456 457 last := int32(3) 458 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 459 require.NoError(t, err) 460 461 got, pageInfo, err := ns.GetNodes(ctx, 1, pagination) 462 require.NoError(t, err) 463 assert.Len(t, got, 3) 464 assert.Equal(t, nodes[7].ID, got[0].ID) 465 assert.Equal(t, nodes[8].ID, got[1].ID) 466 assert.Equal(t, nodes[9].ID, got[2].ID) 467 assert.Equal(t, entities.PageInfo{ 468 HasNextPage: false, 469 HasPreviousPage: true, 470 StartCursor: nodes[7].Cursor().Encode(), 471 EndCursor: nodes[9].Cursor().Encode(), 472 }, pageInfo) 473 } 474 475 func testNodePaginationFirstAfter(t *testing.T) { 476 ctx := tempTransaction(t) 477 478 ns := sqlstore.NewNode(connectionSource) 479 nodes := addPaginationTestNodes(t, ctx, ns) 480 481 first := int32(3) 482 after := nodes[2].Cursor().Encode() 483 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 484 require.NoError(t, err) 485 486 got, pageInfo, err := ns.GetNodes(ctx, 1, pagination) 487 require.NoError(t, err) 488 assert.Len(t, got, 3) 489 assert.Equal(t, nodes[3].ID, got[0].ID) 490 assert.Equal(t, nodes[4].ID, got[1].ID) 491 assert.Equal(t, nodes[5].ID, got[2].ID) 492 assert.Equal(t, entities.PageInfo{ 493 HasNextPage: true, 494 HasPreviousPage: true, 495 StartCursor: nodes[3].Cursor().Encode(), 496 EndCursor: nodes[5].Cursor().Encode(), 497 }, pageInfo) 498 } 499 500 func testNodePaginationLastBefore(t *testing.T) { 501 ctx := tempTransaction(t) 502 503 ns := sqlstore.NewNode(connectionSource) 504 nodes := addPaginationTestNodes(t, ctx, ns) 505 506 last := int32(3) 507 before := nodes[7].Cursor().Encode() 508 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 509 require.NoError(t, err) 510 511 got, pageInfo, err := ns.GetNodes(ctx, 1, pagination) 512 require.NoError(t, err) 513 assert.Len(t, got, 3) 514 assert.Equal(t, nodes[4].ID, got[0].ID) 515 assert.Equal(t, nodes[5].ID, got[1].ID) 516 assert.Equal(t, nodes[6].ID, got[2].ID) 517 assert.Equal(t, entities.PageInfo{ 518 HasNextPage: true, 519 HasPreviousPage: true, 520 StartCursor: nodes[4].Cursor().Encode(), 521 EndCursor: nodes[6].Cursor().Encode(), 522 }, pageInfo) 523 } 524 525 func TestNode_AddRankingScoreInSameEpoch(t *testing.T) { 526 ctx := tempTransaction(t) 527 528 bs := sqlstore.NewBlocks(connectionSource) 529 ns := sqlstore.NewNode(connectionSource) 530 531 block := addTestBlock(t, ctx, bs) 532 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 533 534 // node1 goes from pending -> ersatz -> tendermint 535 // then gets demoted straight to pending with a zero perf score 536 addRankingScore(t, ctx, ns, node1, 537 entities.RankingScore{ 538 StakeScore: decimal.NewFromFloat(0.5), 539 PerformanceScore: decimal.NewFromFloat(0.25), 540 PreviousStatus: entities.ValidatorNodeStatusPending, 541 Status: entities.ValidatorNodeStatusErsatz, 542 EpochSeq: 2, 543 VegaTime: block.VegaTime, 544 }) 545 addRankingScore(t, ctx, ns, node1, 546 entities.RankingScore{ 547 StakeScore: decimal.NewFromFloat(0.5), 548 PerformanceScore: decimal.Zero, 549 PreviousStatus: entities.ValidatorNodeStatusTendermint, 550 Status: entities.ValidatorNodeStatusPending, 551 EpochSeq: 2, 552 VegaTime: block.VegaTime, 553 }) 554 } 555 556 func TestNodeStatusEnum(t *testing.T) { 557 var nodeStatus vegapb.NodeStatus 558 states := getEnums(t, nodeStatus) 559 assert.Len(t, states, 3) 560 for s, state := range states { 561 t.Run(state, func(t *testing.T) { 562 ctx := tempTransaction(t) 563 564 bs := sqlstore.NewBlocks(connectionSource) 565 ns := sqlstore.NewNode(connectionSource) 566 block := addTestBlock(t, ctx, bs) 567 568 node := entities.Node{ 569 ID: entities.NodeID(GenerateID()), 570 PubKey: entities.VegaPublicKey(GenerateID()), 571 TmPubKey: entities.TendermintPublicKey(generateTendermintPublicKey()), 572 EthereumAddress: entities.EthereumAddress(generateEthereumAddress()), 573 VegaTime: block.VegaTime, 574 Status: entities.NodeStatus(s), 575 TxHash: generateTxHash(), 576 } 577 578 require.NoError(t, ns.UpsertNode(ctx, &node)) 579 fetched, err := ns.GetByTxHash(ctx, node.TxHash) 580 assert.NoError(t, err) 581 assert.Len(t, fetched, 1) 582 assert.Equal(t, node.Status, fetched[0].Status) 583 }) 584 } 585 } 586 587 func TestNodeValidatorStatusEnum(t *testing.T) { 588 var validatorNodeStatus vegapb.ValidatorNodeStatus 589 states := getEnums(t, validatorNodeStatus) 590 assert.Len(t, states, 4) 591 592 for s, state := range states { 593 t.Run(state, func(t *testing.T) { 594 ctx := tempTransaction(t) 595 596 bs := sqlstore.NewBlocks(connectionSource) 597 ns := sqlstore.NewNode(connectionSource) 598 599 block := addTestBlock(t, ctx, bs) 600 node1 := addTestNode(t, ctx, ns, block, GenerateID()) 601 score := entities.RankingScore{ 602 StakeScore: decimal.NewFromFloat(0.5), 603 PerformanceScore: decimal.NewFromFloat(0.25), 604 PreviousStatus: entities.ValidatorNodeStatusUnspecified, 605 Status: entities.ValidatorNodeStatus(s), 606 EpochSeq: 1, 607 VegaTime: block.VegaTime, 608 TxHash: generateTxHash(), 609 } 610 addRankingScore(t, ctx, ns, node1, score) 611 var got entities.RankingScore 612 require.NoError(t, pgxscan.Get(ctx, connectionSource, &got, ` 613 SELECT 614 stake_score, 615 performance_score, 616 previous_status, 617 status, 618 voting_power, 619 ranking_score, 620 tx_hash, 621 vega_time 622 FROM ranking_scores WHERE tx_hash = $1`, score.TxHash)) 623 assert.Equal(t, score.Status, got.Status) 624 }) 625 } 626 }