From 17b990924ceb4b91e94c800d78e5f1bbe909b398 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 6 May 2024 13:13:37 -0400 Subject: [PATCH 1/5] Add a SHiP test to verify requesting blocks across Legacy to Savanna --- tests/CMakeLists.txt | 3 + tests/ship_reqs_across_svnn_test.py | 143 ++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100755 tests/ship_reqs_across_svnn_test.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c81a3a872c..e1376c6cb5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -51,6 +51,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-label.sh ${CMAKE_CURRENT_BINA configure_file(${CMAKE_CURRENT_SOURCE_DIR}/full-version-label.sh ${CMAKE_CURRENT_BINARY_DIR}/full-version-label.sh COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/nodeos_producer_watermark_test.py ${CMAKE_CURRENT_BINARY_DIR}/nodeos_producer_watermark_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cli_test.py ${CMAKE_CURRENT_BINARY_DIR}/cli_test.py COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ship_reqs_across_svnn_test.py ${CMAKE_CURRENT_BINARY_DIR}/ship_reqs_across_svnn_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ship_test.py ${CMAKE_CURRENT_BINARY_DIR}/ship_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ship_streamer_test.py ${CMAKE_CURRENT_BINARY_DIR}/ship_streamer_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bridge_for_fork_test_shape.json ${CMAKE_CURRENT_BINARY_DIR}/bridge_for_fork_test_shape.json COPYONLY) @@ -154,6 +155,8 @@ set_property(TEST disaster_recovery PROPERTY LABELS nonparallelizable_tests) add_test(NAME disaster_recovery_2 COMMAND tests/disaster_recovery_2.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST disaster_recovery_2 PROPERTY LABELS nonparallelizable_tests) +add_test(NAME ship_reqs_across_svnn_test COMMAND tests/ship_reqs_across_svnn_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST ship_reqs_across_svnn_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME ship_test COMMAND tests/ship_test.py -v --num-clients 10 --num-requests 5000 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST ship_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME ship_test_unix COMMAND tests/ship_test.py -v --num-clients 10 --num-requests 5000 ${UNSHARE} --unix-socket WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/tests/ship_reqs_across_svnn_test.py b/tests/ship_reqs_across_svnn_test.py new file mode 100755 index 0000000000..28a901856e --- /dev/null +++ b/tests/ship_reqs_across_svnn_test.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +import json +import os +import re +import shutil +import signal + +from TestHarness import Cluster, TestHelper, Utils, WalletMgr + +############################################################### +# ship_legacy_to_svnn +# +# This test verifies SHiP get_blocks_result_v1 works across Legacy and Savanna boundary. +# 1. Start a producer Node and a SHiP node in Legacy mode +# 2. Transition to Savanna +# 3. Start a SHiP client, requesting blocks between block number 1 (pre Savanna) +# and a block whose block number greater than Savanna Genesis block (post Savanna) +# 4. Verify `finality_data` field in every block before Savanna Genesis block is NULL, +# and `finality_data` field in every block after Savanna Genesis block contains a value. +# +############################################################### + +Print=Utils.Print + +args = TestHelper.parse_args({"--dump-error-details","--keep-logs","-v","--leave-running","--unshared"}) + +Utils.Debug=args.v +cluster=Cluster(unshared=args.unshared, keepRunning=args.leave_running, keepLogs=args.keep_logs) +dumpErrorDetails=args.dump_error_details +walletPort=TestHelper.DEFAULT_WALLET_PORT + +totalProducerNodes=1 +totalNonProducerNodes=1 +totalNodes=totalProducerNodes+totalNonProducerNodes + +walletMgr=WalletMgr(True, port=walletPort) +testSuccessful=False + +shipTempDir=None + +try: + TestHelper.printSystemInfo("BEGIN") + + cluster.setWalletMgr(walletMgr) + Print("Stand up cluster") + + shipNodeNum = 1 + specificExtraNodeosArgs={} + specificExtraNodeosArgs[shipNodeNum]="--plugin eosio::state_history_plugin --trace-history --chain-state-history --state-history-stride 200 --plugin eosio::net_api_plugin --plugin eosio::producer_api_plugin --finality-data-history" + + if cluster.launch(topo="mesh", pnodes=totalProducerNodes, totalNodes=totalNodes, + activateIF=True, + specificExtraNodeosArgs=specificExtraNodeosArgs) is False: + Utils.cmdError("launcher") + Utils.errorExit("Failed to stand up cluster.") + + # Verify nodes are in sync and advancing + cluster.waitOnClusterSync(blockAdvancing=5) + Print("Cluster in Sync") + + #Verify nodes are in sync and advancing + cluster.waitOnClusterSync(blockAdvancing=3) + Print("Shutdown unneeded bios node") + cluster.biosNode.kill(signal.SIGTERM) + + shipNode = cluster.getNode(shipNodeNum) + # Block with start_block_num is before Savanna and block with end_block_num is after Savanna + start_block_num = 1 + end_block_num = start_block_num + shipNode.getBlockNum() + + # Start a SHiP client and request blocks between start_block_num and end_block_num + shipClient = "tests/ship_streamer" + cmd = f"{shipClient} --start-block-num {start_block_num} --end-block-num {end_block_num} --fetch-block --fetch-traces --fetch-deltas --fetch-finality-data" + if Utils.Debug: Utils.Print(f"cmd: {cmd}") + shipTempDir = os.path.join(Utils.DataDir, "ship") + os.makedirs(shipTempDir, exist_ok = True) + shipClientFilePrefix = os.path.join(shipTempDir, "client") + clientOutFileName = f"{shipClientFilePrefix}.out" + clientOutFile = open(clientOutFileName, "w") + clientErrFile = open(f"{shipClientFilePrefix}.err", "w") + Print(f"Start client") + popen=Utils.delayedCheckOutput(cmd, stdout=clientOutFile, stderr=clientErrFile) + Print(f"Client started, Ship node head is: {shipNode.getBlockNum()}") + + Print("Wait for SHiP client to finish") + popen.wait() + Print("SHiP client stopped") + clientOutFile.close() + clientErrFile.close() + + Print("Shutdown SHiP node") + shipNode.kill(signal.SIGTERM) + + # Find the Savanna Genesis Block number + svnnGensisBlockNum = 0 + shipStderrFileName=Utils.getNodeDataDir(shipNodeNum, "stderr.txt") + with open(shipStderrFileName, 'r') as f: + line = f.readline() + while line: + match = re.search(r'Transitioning to savanna, IF Genesis Block (\d+)', line) + if match: + svnnGensisBlockNum = int(match.group(1)) + break + line = f.readline() + Print(f"Savanna Genesis Block number: {svnnGensisBlockNum}") + + # Make sure start_block_num is indeed pre Savanna and end_block_num is post Savanna + assert svnnGensisBlockNum > start_block_num, f'svnnGensisBlockNum {svnnGensisBlockNum} must be greater than start_block_num {start_block_num}' + assert svnnGensisBlockNum < end_block_num, f'svnnGensisBlockNum {svnnGensisBlockNum} must be less than end_block_num {end_block_num}' + + Print("Verify ship_client output is well formed") + blocks_result_v1 = None + # Verify SHiP client receives well formed results + with open(clientOutFileName, 'r') as f: + lines = f.readlines() + try: + blocks_result_v1 = json.loads(" ".join(lines)) + except json.decoder.JSONDecodeError as er: + Utils.errorExit(f"ship_client output was malformed. Exception: {er}") + + # Verify `finality_data` field in every block before Savanna Genesis block is Null, + # and `finality_data` field in every block after Savanna Genesis block has a value. + Print("Verify finality_data") + for result in blocks_result_v1: + res = result["get_blocks_result_v1"] + block_num = int(res["this_block"]["block_num"]) + finality_data = res["finality_data"] + + if block_num < svnnGensisBlockNum: + assert finality_data is None, f"finality_data is not Null for block {block_num} before Savanna Genesis Block {svnnGensisBlockNum}" + else: + assert finality_data is not None, f"finality_data is Null for block {block_num} after Savanna Genesis Block {svnnGensisBlockNum}" + + testSuccessful = True +finally: + TestHelper.shutdown(cluster, walletMgr, testSuccessful=testSuccessful, dumpErrorDetails=dumpErrorDetails) + if shipTempDir is not None: + if testSuccessful and not args.keep_logs: + shutil.rmtree(shipTempDir, ignore_errors=True) + +errorCode = 0 if testSuccessful else 1 +exit(errorCode) From a9f61d4492374132beec29becc48d49477ebbe7a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 6 May 2024 13:29:25 -0500 Subject: [PATCH 2/5] dev => beta1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a86853358..c8808f0499 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) set(VERSION_PATCH 0) -set(VERSION_SUFFIX dev) +set(VERSION_SUFFIX beta1) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") From 8f76994cd01aab1b8a7920ae590bbb1ae6e6eb8d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 6 May 2024 14:58:56 -0400 Subject: [PATCH 3/5] Make the test description match the test file name --- tests/ship_reqs_across_svnn_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ship_reqs_across_svnn_test.py b/tests/ship_reqs_across_svnn_test.py index 28a901856e..79d7d8b1c6 100755 --- a/tests/ship_reqs_across_svnn_test.py +++ b/tests/ship_reqs_across_svnn_test.py @@ -9,7 +9,7 @@ from TestHarness import Cluster, TestHelper, Utils, WalletMgr ############################################################### -# ship_legacy_to_svnn +# ship_reqs_across_savanna # # This test verifies SHiP get_blocks_result_v1 works across Legacy and Savanna boundary. # 1. Start a producer Node and a SHiP node in Legacy mode From 82ab54afc4a63c5f4b9b633adce694e088fa5e8c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 6 May 2024 15:16:53 -0500 Subject: [PATCH 4/5] Change back to dev --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8808f0499..8a86853358 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) set(VERSION_PATCH 0) -set(VERSION_SUFFIX beta1) +set(VERSION_SUFFIX dev) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") From 2cbd27d141b670b82277aaa688ab024eadfcfc27 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 6 May 2024 20:04:58 -0400 Subject: [PATCH 5/5] remove duplicate waitOnClusterSync() and do not include start_block_num in end_block_num --- tests/ship_reqs_across_svnn_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/ship_reqs_across_svnn_test.py b/tests/ship_reqs_across_svnn_test.py index 79d7d8b1c6..c43b2c42d7 100755 --- a/tests/ship_reqs_across_svnn_test.py +++ b/tests/ship_reqs_across_svnn_test.py @@ -59,15 +59,13 @@ cluster.waitOnClusterSync(blockAdvancing=5) Print("Cluster in Sync") - #Verify nodes are in sync and advancing - cluster.waitOnClusterSync(blockAdvancing=3) Print("Shutdown unneeded bios node") cluster.biosNode.kill(signal.SIGTERM) shipNode = cluster.getNode(shipNodeNum) # Block with start_block_num is before Savanna and block with end_block_num is after Savanna start_block_num = 1 - end_block_num = start_block_num + shipNode.getBlockNum() + end_block_num = shipNode.getBlockNum() # Start a SHiP client and request blocks between start_block_num and end_block_num shipClient = "tests/ship_streamer"