github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/rpc/client/client_test.go (about) 1 package client 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "testing" 9 "time" 10 11 "github.com/gnolang/gno/tm2/pkg/amino" 12 abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" 13 cstypes "github.com/gnolang/gno/tm2/pkg/bft/consensus/types" 14 ctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" 15 types "github.com/gnolang/gno/tm2/pkg/bft/rpc/lib/types" 16 bfttypes "github.com/gnolang/gno/tm2/pkg/bft/types" 17 "github.com/gnolang/gno/tm2/pkg/p2p" 18 "github.com/stretchr/testify/assert" 19 "github.com/stretchr/testify/require" 20 ) 21 22 // generateMockRequestClient generates a single RPC request mock client 23 func generateMockRequestClient( 24 t *testing.T, 25 method string, 26 verifyParamsFn func(*testing.T, map[string]any), 27 responseData any, 28 ) *mockClient { 29 t.Helper() 30 31 return &mockClient{ 32 sendRequestFn: func( 33 _ context.Context, 34 request types.RPCRequest, 35 ) (*types.RPCResponse, error) { 36 // Validate the request 37 require.Equal(t, "2.0", request.JSONRPC) 38 require.NotNil(t, request.ID) 39 require.Equal(t, request.Method, method) 40 41 // Validate the params 42 var params map[string]any 43 require.NoError(t, json.Unmarshal(request.Params, ¶ms)) 44 45 verifyParamsFn(t, params) 46 47 // Prepare the result 48 result, err := amino.MarshalJSON(responseData) 49 require.NoError(t, err) 50 51 // Prepare the response 52 response := &types.RPCResponse{ 53 JSONRPC: "2.0", 54 ID: request.ID, 55 Result: result, 56 Error: nil, 57 } 58 59 return response, nil 60 }, 61 } 62 } 63 64 // generateMockRequestsClient generates a batch RPC request mock client 65 func generateMockRequestsClient( 66 t *testing.T, 67 method string, 68 verifyParamsFn func(*testing.T, map[string]any), 69 responseData []any, 70 ) *mockClient { 71 t.Helper() 72 73 return &mockClient{ 74 sendBatchFn: func( 75 _ context.Context, 76 requests types.RPCRequests, 77 ) (types.RPCResponses, error) { 78 responses := make(types.RPCResponses, 0, len(requests)) 79 80 // Validate the requests 81 for index, r := range requests { 82 require.Equal(t, "2.0", r.JSONRPC) 83 require.NotNil(t, r.ID) 84 require.Equal(t, r.Method, method) 85 86 // Validate the params 87 var params map[string]any 88 require.NoError(t, json.Unmarshal(r.Params, ¶ms)) 89 90 verifyParamsFn(t, params) 91 92 // Prepare the result 93 result, err := amino.MarshalJSON(responseData[index]) 94 require.NoError(t, err) 95 96 // Prepare the response 97 response := types.RPCResponse{ 98 JSONRPC: "2.0", 99 ID: r.ID, 100 Result: result, 101 Error: nil, 102 } 103 104 responses = append(responses, response) 105 } 106 107 return responses, nil 108 }, 109 } 110 } 111 112 func TestRPCClient_Status(t *testing.T) { 113 t.Parallel() 114 115 var ( 116 expectedStatus = &ctypes.ResultStatus{ 117 NodeInfo: p2p.NodeInfo{ 118 Moniker: "dummy", 119 }, 120 } 121 122 verifyFn = func(t *testing.T, params map[string]any) { 123 t.Helper() 124 125 assert.Len(t, params, 0) 126 } 127 128 mockClient = generateMockRequestClient( 129 t, 130 statusMethod, 131 verifyFn, 132 expectedStatus, 133 ) 134 ) 135 136 // Create the client 137 c := NewRPCClient(mockClient) 138 139 // Get the status 140 status, err := c.Status() 141 require.NoError(t, err) 142 143 assert.Equal(t, expectedStatus, status) 144 } 145 146 func TestRPCClient_ABCIInfo(t *testing.T) { 147 t.Parallel() 148 149 var ( 150 expectedInfo = &ctypes.ResultABCIInfo{ 151 Response: abci.ResponseInfo{ 152 LastBlockAppHash: []byte("dummy"), 153 }, 154 } 155 156 verifyFn = func(t *testing.T, params map[string]any) { 157 t.Helper() 158 159 assert.Len(t, params, 0) 160 } 161 162 mockClient = generateMockRequestClient( 163 t, 164 abciInfoMethod, 165 verifyFn, 166 expectedInfo, 167 ) 168 ) 169 170 // Create the client 171 c := NewRPCClient(mockClient) 172 173 // Get the info 174 info, err := c.ABCIInfo() 175 require.NoError(t, err) 176 177 assert.Equal(t, expectedInfo, info) 178 } 179 180 func TestRPCClient_ABCIQuery(t *testing.T) { 181 t.Parallel() 182 183 var ( 184 path = "path" 185 data = []byte("data") 186 opts = DefaultABCIQueryOptions 187 188 expectedQuery = &ctypes.ResultABCIQuery{ 189 Response: abci.ResponseQuery{ 190 Value: []byte("dummy"), 191 }, 192 } 193 194 verifyFn = func(t *testing.T, params map[string]any) { 195 t.Helper() 196 197 assert.Equal(t, path, params["path"]) 198 assert.Equal(t, base64.StdEncoding.EncodeToString(data), params["data"]) 199 assert.Equal(t, fmt.Sprintf("%d", opts.Height), params["height"]) 200 assert.Equal(t, opts.Prove, params["prove"]) 201 } 202 203 mockClient = generateMockRequestClient( 204 t, 205 abciQueryMethod, 206 verifyFn, 207 expectedQuery, 208 ) 209 ) 210 211 // Create the client 212 c := NewRPCClient(mockClient) 213 214 // Get the query 215 query, err := c.ABCIQuery(path, data) 216 require.NoError(t, err) 217 218 assert.Equal(t, expectedQuery, query) 219 } 220 221 func TestRPCClient_BroadcastTxCommit(t *testing.T) { 222 t.Parallel() 223 224 var ( 225 tx = []byte("tx") 226 227 expectedTxCommit = &ctypes.ResultBroadcastTxCommit{ 228 Hash: []byte("dummy"), 229 } 230 231 verifyFn = func(t *testing.T, params map[string]any) { 232 t.Helper() 233 234 assert.Equal(t, base64.StdEncoding.EncodeToString(tx), params["tx"]) 235 } 236 237 mockClient = generateMockRequestClient( 238 t, 239 broadcastTxCommitMethod, 240 verifyFn, 241 expectedTxCommit, 242 ) 243 ) 244 245 // Create the client 246 c := NewRPCClient(mockClient) 247 248 // Get the broadcast 249 txCommit, err := c.BroadcastTxCommit(tx) 250 require.NoError(t, err) 251 252 assert.Equal(t, expectedTxCommit, txCommit) 253 } 254 255 func TestRPCClient_BroadcastTxAsync(t *testing.T) { 256 t.Parallel() 257 258 var ( 259 tx = []byte("tx") 260 261 expectedTxBroadcast = &ctypes.ResultBroadcastTx{ 262 Hash: []byte("dummy"), 263 } 264 265 verifyFn = func(t *testing.T, params map[string]any) { 266 t.Helper() 267 268 assert.Equal(t, base64.StdEncoding.EncodeToString(tx), params["tx"]) 269 } 270 271 mockClient = generateMockRequestClient( 272 t, 273 broadcastTxAsyncMethod, 274 verifyFn, 275 expectedTxBroadcast, 276 ) 277 ) 278 279 // Create the client 280 c := NewRPCClient(mockClient) 281 282 // Get the broadcast 283 txAsync, err := c.BroadcastTxAsync(tx) 284 require.NoError(t, err) 285 286 assert.Equal(t, expectedTxBroadcast, txAsync) 287 } 288 289 func TestRPCClient_BroadcastTxSync(t *testing.T) { 290 t.Parallel() 291 292 var ( 293 tx = []byte("tx") 294 295 expectedTxBroadcast = &ctypes.ResultBroadcastTx{ 296 Hash: []byte("dummy"), 297 } 298 299 verifyFn = func(t *testing.T, params map[string]any) { 300 t.Helper() 301 302 assert.Equal(t, base64.StdEncoding.EncodeToString(tx), params["tx"]) 303 } 304 305 mockClient = generateMockRequestClient( 306 t, 307 broadcastTxSyncMethod, 308 verifyFn, 309 expectedTxBroadcast, 310 ) 311 ) 312 313 // Create the client 314 c := NewRPCClient(mockClient) 315 316 // Get the broadcast 317 txSync, err := c.BroadcastTxSync(tx) 318 require.NoError(t, err) 319 320 assert.Equal(t, expectedTxBroadcast, txSync) 321 } 322 323 func TestRPCClient_UnconfirmedTxs(t *testing.T) { 324 t.Parallel() 325 326 var ( 327 limit = 10 328 329 expectedResult = &ctypes.ResultUnconfirmedTxs{ 330 Count: 10, 331 } 332 333 verifyFn = func(t *testing.T, params map[string]any) { 334 t.Helper() 335 336 assert.Equal(t, fmt.Sprintf("%d", limit), params["limit"]) 337 } 338 339 mockClient = generateMockRequestClient( 340 t, 341 unconfirmedTxsMethod, 342 verifyFn, 343 expectedResult, 344 ) 345 ) 346 347 // Create the client 348 c := NewRPCClient(mockClient) 349 350 // Get the result 351 result, err := c.UnconfirmedTxs(limit) 352 require.NoError(t, err) 353 354 assert.Equal(t, expectedResult, result) 355 } 356 357 func TestRPCClient_NumUnconfirmedTxs(t *testing.T) { 358 t.Parallel() 359 360 var ( 361 expectedResult = &ctypes.ResultUnconfirmedTxs{ 362 Count: 10, 363 } 364 365 verifyFn = func(t *testing.T, params map[string]any) { 366 t.Helper() 367 368 assert.Len(t, params, 0) 369 } 370 371 mockClient = generateMockRequestClient( 372 t, 373 numUnconfirmedTxsMethod, 374 verifyFn, 375 expectedResult, 376 ) 377 ) 378 379 // Create the client 380 c := NewRPCClient(mockClient) 381 382 // Get the result 383 result, err := c.NumUnconfirmedTxs() 384 require.NoError(t, err) 385 386 assert.Equal(t, expectedResult, result) 387 } 388 389 func TestRPCClient_NetInfo(t *testing.T) { 390 t.Parallel() 391 392 var ( 393 expectedResult = &ctypes.ResultNetInfo{ 394 NPeers: 10, 395 } 396 397 verifyFn = func(t *testing.T, params map[string]any) { 398 t.Helper() 399 400 assert.Len(t, params, 0) 401 } 402 403 mockClient = generateMockRequestClient( 404 t, 405 netInfoMethod, 406 verifyFn, 407 expectedResult, 408 ) 409 ) 410 411 // Create the client 412 c := NewRPCClient(mockClient) 413 414 // Get the result 415 result, err := c.NetInfo() 416 require.NoError(t, err) 417 418 assert.Equal(t, expectedResult, result) 419 } 420 421 func TestRPCClient_DumpConsensusState(t *testing.T) { 422 t.Parallel() 423 424 var ( 425 expectedResult = &ctypes.ResultDumpConsensusState{ 426 RoundState: &cstypes.RoundState{ 427 Round: 10, 428 }, 429 } 430 431 verifyFn = func(t *testing.T, params map[string]any) { 432 t.Helper() 433 434 assert.Len(t, params, 0) 435 } 436 437 mockClient = generateMockRequestClient( 438 t, 439 dumpConsensusStateMethod, 440 verifyFn, 441 expectedResult, 442 ) 443 ) 444 445 // Create the client 446 c := NewRPCClient(mockClient) 447 448 // Get the result 449 result, err := c.DumpConsensusState() 450 require.NoError(t, err) 451 452 assert.Equal(t, expectedResult, result) 453 } 454 455 func TestRPCClient_ConsensusState(t *testing.T) { 456 t.Parallel() 457 458 var ( 459 expectedResult = &ctypes.ResultConsensusState{ 460 RoundState: cstypes.RoundStateSimple{ 461 ProposalBlockHash: []byte("dummy"), 462 }, 463 } 464 465 verifyFn = func(t *testing.T, params map[string]any) { 466 t.Helper() 467 468 assert.Len(t, params, 0) 469 } 470 471 mockClient = generateMockRequestClient( 472 t, 473 consensusStateMethod, 474 verifyFn, 475 expectedResult, 476 ) 477 ) 478 479 // Create the client 480 c := NewRPCClient(mockClient) 481 482 // Get the result 483 result, err := c.ConsensusState() 484 require.NoError(t, err) 485 486 assert.Equal(t, expectedResult, result) 487 } 488 489 func TestRPCClient_ConsensusParams(t *testing.T) { 490 t.Parallel() 491 492 var ( 493 blockHeight = int64(10) 494 495 expectedResult = &ctypes.ResultConsensusParams{ 496 BlockHeight: blockHeight, 497 } 498 499 verifyFn = func(t *testing.T, params map[string]any) { 500 t.Helper() 501 502 assert.Equal(t, fmt.Sprintf("%d", blockHeight), params["height"]) 503 } 504 505 mockClient = generateMockRequestClient( 506 t, 507 consensusParamsMethod, 508 verifyFn, 509 expectedResult, 510 ) 511 ) 512 513 // Create the client 514 c := NewRPCClient(mockClient) 515 516 // Get the result 517 result, err := c.ConsensusParams(&blockHeight) 518 require.NoError(t, err) 519 520 assert.Equal(t, expectedResult, result) 521 } 522 523 func TestRPCClient_Health(t *testing.T) { 524 t.Parallel() 525 526 var ( 527 expectedResult = &ctypes.ResultHealth{} 528 529 verifyFn = func(t *testing.T, params map[string]any) { 530 t.Helper() 531 532 assert.Len(t, params, 0) 533 } 534 535 mockClient = generateMockRequestClient( 536 t, 537 healthMethod, 538 verifyFn, 539 expectedResult, 540 ) 541 ) 542 543 // Create the client 544 c := NewRPCClient(mockClient) 545 546 // Get the result 547 result, err := c.Health() 548 require.NoError(t, err) 549 550 assert.Equal(t, expectedResult, result) 551 } 552 553 func TestRPCClient_BlockchainInfo(t *testing.T) { 554 t.Parallel() 555 556 var ( 557 minHeight = int64(5) 558 maxHeight = int64(10) 559 560 expectedResult = &ctypes.ResultBlockchainInfo{ 561 LastHeight: 100, 562 } 563 564 verifyFn = func(t *testing.T, params map[string]any) { 565 t.Helper() 566 567 assert.Equal(t, fmt.Sprintf("%d", minHeight), params["minHeight"]) 568 assert.Equal(t, fmt.Sprintf("%d", maxHeight), params["maxHeight"]) 569 } 570 571 mockClient = generateMockRequestClient( 572 t, 573 blockchainMethod, 574 verifyFn, 575 expectedResult, 576 ) 577 ) 578 579 // Create the client 580 c := NewRPCClient(mockClient) 581 582 // Get the result 583 result, err := c.BlockchainInfo(minHeight, maxHeight) 584 require.NoError(t, err) 585 586 assert.Equal(t, expectedResult, result) 587 } 588 589 func TestRPCClient_Genesis(t *testing.T) { 590 t.Parallel() 591 592 var ( 593 expectedResult = &ctypes.ResultGenesis{ 594 Genesis: &bfttypes.GenesisDoc{ 595 ChainID: "dummy", 596 }, 597 } 598 599 verifyFn = func(t *testing.T, params map[string]any) { 600 t.Helper() 601 602 assert.Len(t, params, 0) 603 } 604 605 mockClient = generateMockRequestClient( 606 t, 607 genesisMethod, 608 verifyFn, 609 expectedResult, 610 ) 611 ) 612 613 // Create the client 614 c := NewRPCClient(mockClient) 615 616 // Get the result 617 result, err := c.Genesis() 618 require.NoError(t, err) 619 620 assert.Equal(t, expectedResult, result) 621 } 622 623 func TestRPCClient_Block(t *testing.T) { 624 t.Parallel() 625 626 var ( 627 height = int64(10) 628 629 expectedResult = &ctypes.ResultBlock{ 630 BlockMeta: &bfttypes.BlockMeta{ 631 Header: bfttypes.Header{ 632 Height: height, 633 }, 634 }, 635 } 636 637 verifyFn = func(t *testing.T, params map[string]any) { 638 t.Helper() 639 640 assert.Equal(t, fmt.Sprintf("%d", height), params["height"]) 641 } 642 643 mockClient = generateMockRequestClient( 644 t, 645 blockMethod, 646 verifyFn, 647 expectedResult, 648 ) 649 ) 650 651 // Create the client 652 c := NewRPCClient(mockClient) 653 654 // Get the result 655 result, err := c.Block(&height) 656 require.NoError(t, err) 657 658 assert.Equal(t, expectedResult, result) 659 } 660 661 func TestRPCClient_BlockResults(t *testing.T) { 662 t.Parallel() 663 664 var ( 665 height = int64(10) 666 667 expectedResult = &ctypes.ResultBlockResults{ 668 Height: height, 669 } 670 671 verifyFn = func(t *testing.T, params map[string]any) { 672 t.Helper() 673 674 assert.Equal(t, fmt.Sprintf("%d", height), params["height"]) 675 } 676 677 mockClient = generateMockRequestClient( 678 t, 679 blockResultsMethod, 680 verifyFn, 681 expectedResult, 682 ) 683 ) 684 685 // Create the client 686 c := NewRPCClient(mockClient) 687 688 // Get the result 689 result, err := c.BlockResults(&height) 690 require.NoError(t, err) 691 692 assert.Equal(t, expectedResult, result) 693 } 694 695 func TestRPCClient_Commit(t *testing.T) { 696 t.Parallel() 697 698 var ( 699 height = int64(10) 700 701 expectedResult = &ctypes.ResultCommit{ 702 CanonicalCommit: true, 703 } 704 705 verifyFn = func(t *testing.T, params map[string]any) { 706 t.Helper() 707 708 assert.Equal(t, fmt.Sprintf("%d", height), params["height"]) 709 } 710 711 mockClient = generateMockRequestClient( 712 t, 713 commitMethod, 714 verifyFn, 715 expectedResult, 716 ) 717 ) 718 719 // Create the client 720 c := NewRPCClient(mockClient) 721 722 // Get the result 723 result, err := c.Commit(&height) 724 require.NoError(t, err) 725 726 assert.Equal(t, expectedResult, result) 727 } 728 729 func TestRPCClient_Tx(t *testing.T) { 730 t.Parallel() 731 732 var ( 733 hash = []byte("tx hash") 734 735 expectedResult = &ctypes.ResultTx{ 736 Hash: hash, 737 Height: 10, 738 } 739 740 verifyFn = func(t *testing.T, params map[string]any) { 741 t.Helper() 742 743 assert.Equal(t, base64.StdEncoding.EncodeToString(hash), params["hash"]) 744 } 745 746 mockClient = generateMockRequestClient( 747 t, 748 txMethod, 749 verifyFn, 750 expectedResult, 751 ) 752 ) 753 754 // Create the client 755 c := NewRPCClient(mockClient) 756 757 // Get the result 758 result, err := c.Tx(hash) 759 require.NoError(t, err) 760 761 assert.Equal(t, expectedResult, result) 762 } 763 764 func TestRPCClient_Validators(t *testing.T) { 765 t.Parallel() 766 767 var ( 768 height = int64(10) 769 770 expectedResult = &ctypes.ResultValidators{ 771 BlockHeight: height, 772 } 773 774 verifyFn = func(t *testing.T, params map[string]any) { 775 t.Helper() 776 777 assert.Equal(t, fmt.Sprintf("%d", height), params["height"]) 778 } 779 780 mockClient = generateMockRequestClient( 781 t, 782 validatorsMethod, 783 verifyFn, 784 expectedResult, 785 ) 786 ) 787 788 // Create the client 789 c := NewRPCClient(mockClient) 790 791 // Get the result 792 result, err := c.Validators(&height) 793 require.NoError(t, err) 794 795 assert.Equal(t, expectedResult, result) 796 } 797 798 func TestRPCClient_Batch(t *testing.T) { 799 t.Parallel() 800 801 convertResults := func(results []*ctypes.ResultStatus) []any { 802 res := make([]any, len(results)) 803 804 for index, item := range results { 805 res[index] = item 806 } 807 808 return res 809 } 810 811 var ( 812 expectedStatuses = []*ctypes.ResultStatus{ 813 { 814 NodeInfo: p2p.NodeInfo{ 815 Moniker: "dummy", 816 }, 817 }, 818 { 819 NodeInfo: p2p.NodeInfo{ 820 Moniker: "dummy", 821 }, 822 }, 823 { 824 NodeInfo: p2p.NodeInfo{ 825 Moniker: "dummy", 826 }, 827 }, 828 } 829 830 verifyFn = func(t *testing.T, params map[string]any) { 831 t.Helper() 832 833 assert.Len(t, params, 0) 834 } 835 836 mockClient = generateMockRequestsClient( 837 t, 838 statusMethod, 839 verifyFn, 840 convertResults(expectedStatuses), 841 ) 842 ) 843 844 // Create the client 845 c := NewRPCClient(mockClient) 846 847 // Create the batch 848 batch := c.NewBatch() 849 850 require.NoError(t, batch.Status()) 851 require.NoError(t, batch.Status()) 852 require.NoError(t, batch.Status()) 853 854 require.EqualValues(t, 3, batch.Count()) 855 856 // Send the batch 857 ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second) 858 defer cancelFn() 859 860 results, err := batch.Send(ctx) 861 require.NoError(t, err) 862 863 require.Len(t, results, len(expectedStatuses)) 864 865 for index, result := range results { 866 castResult, ok := result.(*ctypes.ResultStatus) 867 require.True(t, ok) 868 869 assert.Equal(t, expectedStatuses[index], castResult) 870 } 871 }