github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/rpc/client/rpc_test.go (about) 1 package client_test 2 3 import ( 4 "context" 5 "encoding/base64" 6 "fmt" 7 "math" 8 "net/http" 9 "strings" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 abci "github.com/badrootd/celestia-core/abci/types" 18 cmtjson "github.com/badrootd/celestia-core/libs/json" 19 "github.com/badrootd/celestia-core/libs/log" 20 cmtmath "github.com/badrootd/celestia-core/libs/math" 21 mempl "github.com/badrootd/celestia-core/mempool" 22 "github.com/badrootd/celestia-core/rpc/client" 23 rpchttp "github.com/badrootd/celestia-core/rpc/client/http" 24 rpclocal "github.com/badrootd/celestia-core/rpc/client/local" 25 ctypes "github.com/badrootd/celestia-core/rpc/core/types" 26 rpcclient "github.com/badrootd/celestia-core/rpc/jsonrpc/client" 27 rpctest "github.com/badrootd/celestia-core/rpc/test" 28 "github.com/badrootd/celestia-core/types" 29 ) 30 31 var ( 32 ctx = context.Background() 33 ) 34 35 func getHTTPClient() *rpchttp.HTTP { 36 rpcAddr := rpctest.GetConfig().RPC.ListenAddress 37 c, err := rpchttp.New(rpcAddr, "/websocket") 38 if err != nil { 39 panic(err) 40 } 41 c.SetLogger(log.TestingLogger()) 42 return c 43 } 44 45 func getHTTPClientWithTimeout(timeout uint) *rpchttp.HTTP { 46 rpcAddr := rpctest.GetConfig().RPC.ListenAddress 47 c, err := rpchttp.NewWithTimeout(rpcAddr, "/websocket", timeout) 48 if err != nil { 49 panic(err) 50 } 51 c.SetLogger(log.TestingLogger()) 52 return c 53 } 54 55 func getLocalClient() *rpclocal.Local { 56 return rpclocal.New(node) 57 } 58 59 // GetClients returns a slice of clients for table-driven tests 60 func GetClients() []client.Client { 61 return []client.Client{ 62 getHTTPClient(), 63 getLocalClient(), 64 } 65 } 66 67 func TestNilCustomHTTPClient(t *testing.T) { 68 require.Panics(t, func() { 69 _, _ = rpchttp.NewWithClient("http://example.com", "/websocket", nil) 70 }) 71 require.Panics(t, func() { 72 _, _ = rpcclient.NewWithHTTPClient("http://example.com", nil) 73 }) 74 } 75 76 func TestCustomHTTPClient(t *testing.T) { 77 remote := rpctest.GetConfig().RPC.ListenAddress 78 c, err := rpchttp.NewWithClient(remote, "/websocket", http.DefaultClient) 79 require.Nil(t, err) 80 status, err := c.Status(context.Background()) 81 require.NoError(t, err) 82 require.NotNil(t, status) 83 } 84 85 func TestCorsEnabled(t *testing.T) { 86 origin := rpctest.GetConfig().RPC.CORSAllowedOrigins[0] 87 remote := strings.ReplaceAll(rpctest.GetConfig().RPC.ListenAddress, "tcp", "http") 88 89 req, err := http.NewRequest("GET", remote, nil) 90 require.Nil(t, err, "%+v", err) 91 req.Header.Set("Origin", origin) 92 c := &http.Client{} 93 resp, err := c.Do(req) 94 require.Nil(t, err, "%+v", err) 95 defer resp.Body.Close() 96 97 assert.Equal(t, resp.Header.Get("Access-Control-Allow-Origin"), origin) 98 } 99 100 // Make sure status is correct (we connect properly) 101 func TestStatus(t *testing.T) { 102 for i, c := range GetClients() { 103 moniker := rpctest.GetConfig().Moniker 104 status, err := c.Status(context.Background()) 105 require.Nil(t, err, "%d: %+v", i, err) 106 assert.Equal(t, moniker, status.NodeInfo.Moniker) 107 } 108 } 109 110 // Make sure info is correct (we connect properly) 111 func TestInfo(t *testing.T) { 112 for i, c := range GetClients() { 113 // status, err := c.Status() 114 // require.Nil(t, err, "%+v", err) 115 info, err := c.ABCIInfo(context.Background()) 116 require.Nil(t, err, "%d: %+v", i, err) 117 // TODO: this is not correct - fix merkleeyes! 118 // assert.EqualValues(t, status.SyncInfo.LatestBlockHeight, info.Response.LastBlockHeight) 119 assert.True(t, strings.Contains(info.Response.Data, "size")) 120 } 121 } 122 123 func TestNetInfo(t *testing.T) { 124 for i, c := range GetClients() { 125 nc, ok := c.(client.NetworkClient) 126 require.True(t, ok, "%d", i) 127 netinfo, err := nc.NetInfo(context.Background()) 128 require.Nil(t, err, "%d: %+v", i, err) 129 assert.True(t, netinfo.Listening) 130 assert.Equal(t, 0, len(netinfo.Peers)) 131 } 132 } 133 134 func TestDumpConsensusState(t *testing.T) { 135 for i, c := range GetClients() { 136 // FIXME: fix server so it doesn't panic on invalid input 137 nc, ok := c.(client.NetworkClient) 138 require.True(t, ok, "%d", i) 139 cons, err := nc.DumpConsensusState(context.Background()) 140 require.Nil(t, err, "%d: %+v", i, err) 141 assert.NotEmpty(t, cons.RoundState) 142 assert.Empty(t, cons.Peers) 143 } 144 } 145 146 func TestConsensusState(t *testing.T) { 147 for i, c := range GetClients() { 148 // FIXME: fix server so it doesn't panic on invalid input 149 nc, ok := c.(client.NetworkClient) 150 require.True(t, ok, "%d", i) 151 cons, err := nc.ConsensusState(context.Background()) 152 require.Nil(t, err, "%d: %+v", i, err) 153 assert.NotEmpty(t, cons.RoundState) 154 } 155 } 156 157 func TestHealth(t *testing.T) { 158 for i, c := range GetClients() { 159 nc, ok := c.(client.NetworkClient) 160 require.True(t, ok, "%d", i) 161 _, err := nc.Health(context.Background()) 162 require.Nil(t, err, "%d: %+v", i, err) 163 } 164 } 165 166 func TestGenesisAndValidators(t *testing.T) { 167 for i, c := range GetClients() { 168 169 // make sure this is the right genesis file 170 gen, err := c.Genesis(context.Background()) 171 require.Nil(t, err, "%d: %+v", i, err) 172 // get the genesis validator 173 require.Equal(t, 1, len(gen.Genesis.Validators)) 174 gval := gen.Genesis.Validators[0] 175 176 // get the current validators 177 h := int64(1) 178 vals, err := c.Validators(context.Background(), &h, nil, nil) 179 require.Nil(t, err, "%d: %+v", i, err) 180 require.Equal(t, 1, len(vals.Validators)) 181 require.Equal(t, 1, vals.Count) 182 require.Equal(t, 1, vals.Total) 183 val := vals.Validators[0] 184 185 // make sure the current set is also the genesis set 186 assert.Equal(t, gval.Power, val.VotingPower) 187 assert.Equal(t, gval.PubKey, val.PubKey) 188 } 189 } 190 191 func TestGenesisChunked(t *testing.T) { 192 ctx, cancel := context.WithCancel(context.Background()) 193 defer cancel() 194 195 for _, c := range GetClients() { 196 first, err := c.GenesisChunked(ctx, 0) 197 require.NoError(t, err) 198 199 decoded := make([]string, 0, first.TotalChunks) 200 for i := 0; i < first.TotalChunks; i++ { 201 chunk, err := c.GenesisChunked(ctx, uint(i)) 202 require.NoError(t, err) 203 data, err := base64.StdEncoding.DecodeString(chunk.Data) 204 require.NoError(t, err) 205 decoded = append(decoded, string(data)) 206 207 } 208 doc := []byte(strings.Join(decoded, "")) 209 210 var out types.GenesisDoc 211 require.NoError(t, cmtjson.Unmarshal(doc, &out), 212 "first: %+v, doc: %s", first, string(doc)) 213 } 214 } 215 216 func TestABCIQuery(t *testing.T) { 217 for i, c := range GetClients() { 218 // write something 219 k, v, tx := MakeTxKV() 220 bres, err := c.BroadcastTxCommit(context.Background(), tx) 221 require.Nil(t, err, "%d: %+v", i, err) 222 apph := bres.Height + 1 // this is where the tx will be applied to the state 223 224 // wait before querying 225 err = client.WaitForHeight(c, apph, nil) 226 require.NoError(t, err) 227 res, err := c.ABCIQuery(context.Background(), "/key", k) 228 qres := res.Response 229 if assert.Nil(t, err) && assert.True(t, qres.IsOK()) { 230 assert.EqualValues(t, v, qres.Value) 231 } 232 } 233 } 234 235 // Make some app checks 236 func TestAppCalls(t *testing.T) { 237 assert, require := assert.New(t), require.New(t) 238 for i, c := range GetClients() { 239 240 // get an offset of height to avoid racing and guessing 241 s, err := c.Status(context.Background()) 242 require.NoError(err) 243 // sh is start height or status height 244 sh := s.SyncInfo.LatestBlockHeight 245 246 // look for the future 247 h := sh + 20 248 _, err = c.Block(context.Background(), &h) 249 require.Error(err) // no block yet 250 251 // write something 252 k, v, tx := MakeTxKV() 253 bres, err := c.BroadcastTxCommit(context.Background(), tx) 254 require.NoError(err) 255 require.True(bres.DeliverTx.IsOK()) 256 txh := bres.Height 257 apph := txh + 1 // this is where the tx will be applied to the state 258 259 // wait before querying 260 err = client.WaitForHeight(c, apph, nil) 261 require.NoError(err) 262 263 _qres, err := c.ABCIQueryWithOptions(context.Background(), "/key", k, client.ABCIQueryOptions{Prove: false}) 264 require.NoError(err) 265 qres := _qres.Response 266 if assert.True(qres.IsOK()) { 267 assert.Equal(k, qres.Key) 268 assert.EqualValues(v, qres.Value) 269 } 270 271 // make sure we can lookup the tx with proof 272 ptx, err := c.Tx(context.Background(), bres.Hash, true) 273 require.NoError(err) 274 assert.EqualValues(txh, ptx.Height) 275 assert.EqualValues(tx, ptx.Tx) 276 277 // and we can even check the block is added 278 block, err := c.Block(context.Background(), &apph) 279 require.NoError(err) 280 appHash := block.Block.Header.AppHash 281 assert.True(len(appHash) > 0) 282 assert.EqualValues(apph, block.Block.Header.Height) 283 284 blockByHash, err := c.BlockByHash(context.Background(), block.BlockID.Hash) 285 require.NoError(err) 286 require.Equal(block, blockByHash) 287 288 // check that the header matches the block hash 289 header, err := c.Header(context.Background(), &apph) 290 require.NoError(err) 291 require.Equal(block.Block.Header, *header.Header) 292 293 headerByHash, err := c.HeaderByHash(context.Background(), block.BlockID.Hash) 294 require.NoError(err) 295 require.Equal(header, headerByHash) 296 297 // now check the results 298 blockResults, err := c.BlockResults(context.Background(), &txh) 299 require.Nil(err, "%d: %+v", i, err) 300 assert.Equal(txh, blockResults.Height) 301 if assert.Equal(1, len(blockResults.TxsResults)) { 302 // check success code 303 assert.EqualValues(0, blockResults.TxsResults[0].Code) 304 } 305 306 // check blockchain info, now that we know there is info 307 info, err := c.BlockchainInfo(context.Background(), apph, apph) 308 require.NoError(err) 309 assert.True(info.LastHeight >= apph) 310 if assert.Equal(1, len(info.BlockMetas)) { 311 lastMeta := info.BlockMetas[0] 312 assert.EqualValues(apph, lastMeta.Header.Height) 313 blockData := block.Block 314 assert.Equal(blockData.Header.AppHash, lastMeta.Header.AppHash) 315 assert.Equal(block.BlockID, lastMeta.BlockID) 316 } 317 318 // and get the corresponding commit with the same apphash 319 commit, err := c.Commit(context.Background(), &apph) 320 require.NoError(err) 321 cappHash := commit.Header.AppHash 322 assert.Equal(appHash, cappHash) 323 assert.NotNil(commit.Commit) 324 325 // compare the commits (note Commit(2) has commit from Block(3)) 326 h = apph - 1 327 commit2, err := c.Commit(context.Background(), &h) 328 require.NoError(err) 329 assert.Equal(block.Block.LastCommitHash, commit2.Commit.Hash()) 330 331 // and we got a proof that works! 332 _pres, err := c.ABCIQueryWithOptions(context.Background(), "/key", k, client.ABCIQueryOptions{Prove: true}) 333 require.NoError(err) 334 pres := _pres.Response 335 assert.True(pres.IsOK()) 336 337 // XXX Test proof 338 } 339 } 340 341 func TestBroadcastTxSync(t *testing.T) { 342 require := require.New(t) 343 344 // TODO (melekes): use mempool which is set on RPC rather than getting it from node 345 mempool := node.Mempool() 346 initMempoolSize := mempool.Size() 347 348 for i, c := range GetClients() { 349 _, _, tx := MakeTxKV() 350 bres, err := c.BroadcastTxSync(context.Background(), tx) 351 require.Nil(err, "%d: %+v", i, err) 352 require.Equal(bres.Code, abci.CodeTypeOK) // FIXME 353 354 require.Equal(initMempoolSize+1, mempool.Size()) 355 356 txs := mempool.ReapMaxTxs(len(tx)) 357 require.EqualValues(tx, txs[0]) 358 mempool.Flush() 359 } 360 } 361 362 func TestBroadcastTxCommit(t *testing.T) { 363 require := require.New(t) 364 365 mempool := node.Mempool() 366 for i, c := range GetClients() { 367 _, _, tx := MakeTxKV() 368 bres, err := c.BroadcastTxCommit(context.Background(), tx) 369 require.Nil(err, "%d: %+v", i, err) 370 require.True(bres.CheckTx.IsOK()) 371 require.True(bres.DeliverTx.IsOK()) 372 373 require.Equal(0, mempool.Size()) 374 } 375 } 376 377 func TestUnconfirmedTxs(t *testing.T) { 378 _, _, tx := MakeTxKV() 379 380 ch := make(chan *abci.Response, 1) 381 mempool := node.Mempool() 382 err := mempool.CheckTx(tx, func(resp *abci.Response) { ch <- resp }, mempl.TxInfo{}) 383 require.NoError(t, err) 384 385 // wait for tx to arrive in mempoool. 386 select { 387 case <-ch: 388 case <-time.After(5 * time.Second): 389 t.Error("Timed out waiting for CheckTx callback") 390 } 391 392 for _, c := range GetClients() { 393 mc := c.(client.MempoolClient) 394 limit := 1 395 res, err := mc.UnconfirmedTxs(context.Background(), &limit) 396 require.NoError(t, err) 397 398 assert.Equal(t, 1, res.Count) 399 assert.Equal(t, 1, res.Total) 400 assert.Equal(t, mempool.SizeBytes(), res.TotalBytes) 401 assert.Exactly(t, types.Txs{tx}, types.Txs(res.Txs)) 402 } 403 404 mempool.Flush() 405 } 406 407 func TestNumUnconfirmedTxs(t *testing.T) { 408 _, _, tx := MakeTxKV() 409 410 ch := make(chan *abci.Response, 1) 411 mempool := node.Mempool() 412 err := mempool.CheckTx(tx, func(resp *abci.Response) { ch <- resp }, mempl.TxInfo{}) 413 require.NoError(t, err) 414 415 // wait for tx to arrive in mempoool. 416 select { 417 case <-ch: 418 case <-time.After(5 * time.Second): 419 t.Error("Timed out waiting for CheckTx callback") 420 } 421 422 mempoolSize := mempool.Size() 423 for i, c := range GetClients() { 424 mc, ok := c.(client.MempoolClient) 425 require.True(t, ok, "%d", i) 426 res, err := mc.NumUnconfirmedTxs(context.Background()) 427 require.Nil(t, err, "%d: %+v", i, err) 428 429 assert.Equal(t, mempoolSize, res.Count) 430 assert.Equal(t, mempoolSize, res.Total) 431 assert.Equal(t, mempool.SizeBytes(), res.TotalBytes) 432 } 433 434 mempool.Flush() 435 } 436 437 func TestCheckTx(t *testing.T) { 438 mempool := node.Mempool() 439 440 for _, c := range GetClients() { 441 _, _, tx := MakeTxKV() 442 443 res, err := c.CheckTx(context.Background(), tx) 444 require.NoError(t, err) 445 assert.Equal(t, abci.CodeTypeOK, res.Code) 446 447 assert.Equal(t, 0, mempool.Size(), "mempool must be empty") 448 } 449 } 450 451 func TestTx(t *testing.T) { 452 // first we broadcast a tx 453 c := getHTTPClient() 454 _, _, tx := MakeTxKV() 455 bres, err := c.BroadcastTxCommit(context.Background(), tx) 456 require.Nil(t, err, "%+v", err) 457 458 txHeight := bres.Height 459 txHash := bres.Hash 460 461 anotherTxHash := types.Tx("a different tx").Hash() 462 463 cases := []struct { 464 valid bool 465 prove bool 466 hash []byte 467 }{ 468 // only valid if correct hash provided 469 {true, false, txHash}, 470 {true, true, txHash}, 471 {false, false, anotherTxHash}, 472 {false, true, anotherTxHash}, 473 {false, false, nil}, 474 {false, true, nil}, 475 } 476 477 for i, c := range GetClients() { 478 for j, tc := range cases { 479 t.Logf("client %d, case %d", i, j) 480 481 // now we query for the tx. 482 // since there's only one tx, we know index=0. 483 ptx, err := c.Tx(context.Background(), tc.hash, tc.prove) 484 485 if !tc.valid { 486 require.NotNil(t, err) 487 } else { 488 require.Nil(t, err, "%+v", err) 489 assert.EqualValues(t, txHeight, ptx.Height) 490 assert.EqualValues(t, tx, ptx.Tx) 491 assert.Zero(t, ptx.Index) 492 assert.True(t, ptx.TxResult.IsOK()) 493 assert.EqualValues(t, txHash, ptx.Hash) 494 } 495 } 496 } 497 } 498 499 func TestTxSearchWithTimeout(t *testing.T) { 500 // Get a client with a time-out of 10 secs. 501 timeoutClient := getHTTPClientWithTimeout(10) 502 503 _, _, tx := MakeTxKV() 504 _, err := timeoutClient.BroadcastTxCommit(context.Background(), tx) 505 require.NoError(t, err) 506 507 // query using a compositeKey (see kvstore application) 508 result, err := timeoutClient.TxSearch(context.Background(), "app.creator='Cosmoshi Netowoko'", false, nil, nil, "asc") 509 require.Nil(t, err) 510 require.Greater(t, len(result.Txs), 0, "expected a lot of transactions") 511 } 512 513 // This test does nothing if we do not call app.SetGenBlockEvents() within main_test.go 514 // It will nevertheless pass as there are no events being generated. 515 func TestBlockSearch(t *testing.T) { 516 c := getHTTPClient() 517 518 // first we broadcast a few txs 519 for i := 0; i < 10; i++ { 520 _, _, tx := MakeTxKV() 521 522 _, err := c.BroadcastTxCommit(context.Background(), tx) 523 require.NoError(t, err) 524 } 525 require.NoError(t, client.WaitForHeight(c, 5, nil)) 526 result, err := c.BlockSearch(context.Background(), "begin_event.foo = 100", nil, nil, "asc") 527 require.NoError(t, err) 528 blockCount := len(result.Blocks) 529 // if we generate block events within the test (by uncommenting 530 // the code in line main_test.go:L23) then we expect len(result.Blocks) 531 // to be at least 5 532 // require.GreaterOrEqual(t, blockCount, 5) 533 534 // otherwise it is 0 535 require.Equal(t, blockCount, 0) 536 537 } 538 func TestTxSearch(t *testing.T) { 539 c := getHTTPClient() 540 541 // first we broadcast a few txs 542 for i := 0; i < 10; i++ { 543 _, _, tx := MakeTxKV() 544 _, err := c.BroadcastTxCommit(context.Background(), tx) 545 require.NoError(t, err) 546 } 547 548 // since we're not using an isolated test server, we'll have lingering transactions 549 // from other tests as well 550 result, err := c.TxSearch(context.Background(), "tx.height >= 0", true, nil, nil, "asc") 551 require.NoError(t, err) 552 txCount := len(result.Txs) 553 554 // pick out the last tx to have something to search for in tests 555 find := result.Txs[len(result.Txs)-1] 556 anotherTxHash := types.Tx("a different tx").Hash() 557 558 for _, c := range GetClients() { 559 560 // now we query for the tx. 561 result, err := c.TxSearch(context.Background(), fmt.Sprintf("tx.hash='%v'", find.Hash), true, nil, nil, "asc") 562 require.Nil(t, err) 563 require.Len(t, result.Txs, 1) 564 require.Equal(t, find.Hash, result.Txs[0].Hash) 565 566 ptx := result.Txs[0] 567 assert.EqualValues(t, find.Height, ptx.Height) 568 assert.EqualValues(t, find.Tx, ptx.Tx) 569 assert.Zero(t, ptx.Index) 570 assert.True(t, ptx.TxResult.IsOK()) 571 assert.EqualValues(t, find.Hash, ptx.Hash) 572 573 // query by height 574 result, err = c.TxSearch(context.Background(), fmt.Sprintf("tx.height=%d", find.Height), true, nil, nil, "asc") 575 require.Nil(t, err) 576 require.Len(t, result.Txs, 1) 577 578 // query for non existing tx 579 result, err = c.TxSearch(context.Background(), fmt.Sprintf("tx.hash='%X'", anotherTxHash), false, nil, nil, "asc") 580 require.Nil(t, err) 581 require.Len(t, result.Txs, 0) 582 583 // query using a compositeKey (see kvstore application) 584 result, err = c.TxSearch(context.Background(), "app.creator='Cosmoshi Netowoko'", false, nil, nil, "asc") 585 require.Nil(t, err) 586 require.Greater(t, len(result.Txs), 0, "expected a lot of transactions") 587 588 // query using an index key 589 result, err = c.TxSearch(context.Background(), "app.index_key='index is working'", false, nil, nil, "asc") 590 require.Nil(t, err) 591 require.Greater(t, len(result.Txs), 0, "expected a lot of transactions") 592 593 // query using an noindex key 594 result, err = c.TxSearch(context.Background(), "app.noindex_key='index is working'", false, nil, nil, "asc") 595 require.Nil(t, err) 596 require.Equal(t, len(result.Txs), 0, "expected a lot of transactions") 597 598 // query using a compositeKey (see kvstore application) and height 599 result, err = c.TxSearch(context.Background(), 600 "app.creator='Cosmoshi Netowoko' AND tx.height<10000", true, nil, nil, "asc") 601 require.Nil(t, err) 602 require.Greater(t, len(result.Txs), 0, "expected a lot of transactions") 603 604 // query a non existing tx with page 1 and txsPerPage 1 605 perPage := 1 606 result, err = c.TxSearch(context.Background(), "app.creator='Cosmoshi Neetowoko'", true, nil, &perPage, "asc") 607 require.Nil(t, err) 608 require.Len(t, result.Txs, 0) 609 610 // check sorting 611 result, err = c.TxSearch(context.Background(), "tx.height >= 1", false, nil, nil, "asc") 612 require.Nil(t, err) 613 for k := 0; k < len(result.Txs)-1; k++ { 614 require.LessOrEqual(t, result.Txs[k].Height, result.Txs[k+1].Height) 615 require.LessOrEqual(t, result.Txs[k].Index, result.Txs[k+1].Index) 616 } 617 618 result, err = c.TxSearch(context.Background(), "tx.height >= 1", false, nil, nil, "desc") 619 require.Nil(t, err) 620 for k := 0; k < len(result.Txs)-1; k++ { 621 require.GreaterOrEqual(t, result.Txs[k].Height, result.Txs[k+1].Height) 622 require.GreaterOrEqual(t, result.Txs[k].Index, result.Txs[k+1].Index) 623 } 624 // check pagination 625 perPage = 3 626 var ( 627 seen = map[int64]bool{} 628 maxHeight int64 629 pages = int(math.Ceil(float64(txCount) / float64(perPage))) 630 ) 631 632 totalTx := 0 633 for page := 1; page <= pages; page++ { 634 page := page 635 result, err := c.TxSearch(context.Background(), "tx.height >= 1", true, &page, &perPage, "asc") 636 require.NoError(t, err) 637 if page < pages { 638 require.Len(t, result.Txs, perPage) 639 } else { 640 require.LessOrEqual(t, len(result.Txs), perPage) 641 } 642 totalTx = totalTx + len(result.Txs) 643 for _, tx := range result.Txs { 644 require.False(t, seen[tx.Height], 645 "Found duplicate height %v in page %v", tx.Height, page) 646 require.Greater(t, tx.Height, maxHeight, 647 "Found decreasing height %v (max seen %v) in page %v", tx.Height, maxHeight, page) 648 seen[tx.Height] = true 649 maxHeight = tx.Height 650 } 651 } 652 require.Equal(t, txCount, totalTx) 653 require.Len(t, seen, txCount) 654 } 655 } 656 657 func TestDataCommitment(t *testing.T) { 658 c := getHTTPClient() 659 660 // first we broadcast a few tx 661 expectedHeight := int64(3) 662 var bres *ctypes.ResultBroadcastTxCommit 663 var err error 664 for i := int64(0); i < expectedHeight; i++ { 665 _, _, tx := MakeTxKV() 666 bres, err = c.BroadcastTxCommit(context.Background(), tx) 667 require.Nil(t, err, "%+v when submitting tx %d", err, i) 668 } 669 670 // check if height >= 3 671 actualHeight := bres.Height 672 require.LessOrEqual(t, expectedHeight, actualHeight, "couldn't create enough blocks for testing the commitment.") 673 674 // check if data commitment is not nil. 675 // Checking if the commitment is correct is done in `core/blocks_test.go`. 676 dataCommitment, err := c.DataCommitment(ctx, 1, uint64(expectedHeight)) 677 require.NotNil(t, dataCommitment, "data commitment shouldn't be nul.") 678 require.Nil(t, err, "%+v when creating data commitment.", err) 679 } 680 681 func TestBatchedJSONRPCCalls(t *testing.T) { 682 c := getHTTPClient() 683 testBatchedJSONRPCCalls(t, c) 684 } 685 686 func testBatchedJSONRPCCalls(t *testing.T, c *rpchttp.HTTP) { 687 k1, v1, tx1 := MakeTxKV() 688 k2, v2, tx2 := MakeTxKV() 689 690 batch := c.NewBatch() 691 r1, err := batch.BroadcastTxCommit(context.Background(), tx1) 692 require.NoError(t, err) 693 r2, err := batch.BroadcastTxCommit(context.Background(), tx2) 694 require.NoError(t, err) 695 require.Equal(t, 2, batch.Count()) 696 bresults, err := batch.Send(ctx) 697 require.NoError(t, err) 698 require.Len(t, bresults, 2) 699 require.Equal(t, 0, batch.Count()) 700 701 bresult1, ok := bresults[0].(*ctypes.ResultBroadcastTxCommit) 702 require.True(t, ok) 703 require.Equal(t, *bresult1, *r1) 704 bresult2, ok := bresults[1].(*ctypes.ResultBroadcastTxCommit) 705 require.True(t, ok) 706 require.Equal(t, *bresult2, *r2) 707 apph := cmtmath.MaxInt64(bresult1.Height, bresult2.Height) + 1 708 709 err = client.WaitForHeight(c, apph, nil) 710 require.NoError(t, err) 711 712 q1, err := batch.ABCIQuery(context.Background(), "/key", k1) 713 require.NoError(t, err) 714 q2, err := batch.ABCIQuery(context.Background(), "/key", k2) 715 require.NoError(t, err) 716 require.Equal(t, 2, batch.Count()) 717 qresults, err := batch.Send(ctx) 718 require.NoError(t, err) 719 require.Len(t, qresults, 2) 720 require.Equal(t, 0, batch.Count()) 721 722 qresult1, ok := qresults[0].(*ctypes.ResultABCIQuery) 723 require.True(t, ok) 724 require.Equal(t, *qresult1, *q1) 725 qresult2, ok := qresults[1].(*ctypes.ResultABCIQuery) 726 require.True(t, ok) 727 require.Equal(t, *qresult2, *q2) 728 729 require.Equal(t, qresult1.Response.Key, k1) 730 require.Equal(t, qresult2.Response.Key, k2) 731 require.Equal(t, qresult1.Response.Value, v1) 732 require.Equal(t, qresult2.Response.Value, v2) 733 } 734 735 func TestBatchedJSONRPCCallsCancellation(t *testing.T) { 736 c := getHTTPClient() 737 _, _, tx1 := MakeTxKV() 738 _, _, tx2 := MakeTxKV() 739 740 batch := c.NewBatch() 741 _, err := batch.BroadcastTxCommit(context.Background(), tx1) 742 require.NoError(t, err) 743 _, err = batch.BroadcastTxCommit(context.Background(), tx2) 744 require.NoError(t, err) 745 // we should have 2 requests waiting 746 require.Equal(t, 2, batch.Count()) 747 // we want to make sure we cleared 2 pending requests 748 require.Equal(t, 2, batch.Clear()) 749 // now there should be no batched requests 750 require.Equal(t, 0, batch.Count()) 751 } 752 753 func TestSendingEmptyRequestBatch(t *testing.T) { 754 c := getHTTPClient() 755 batch := c.NewBatch() 756 _, err := batch.Send(ctx) 757 require.Error(t, err, "sending an empty batch of JSON RPC requests should result in an error") 758 } 759 760 func TestClearingEmptyRequestBatch(t *testing.T) { 761 c := getHTTPClient() 762 batch := c.NewBatch() 763 require.Zero(t, batch.Clear(), "clearing an empty batch of JSON RPC requests should result in a 0 result") 764 } 765 766 func TestConcurrentJSONRPCBatching(t *testing.T) { 767 var wg sync.WaitGroup 768 c := getHTTPClient() 769 for i := 0; i < 50; i++ { 770 wg.Add(1) 771 go func() { 772 defer wg.Done() 773 testBatchedJSONRPCCalls(t, c) 774 }() 775 } 776 wg.Wait() 777 }