Skip to content

Commit

Permalink
Merge pull request #71 from AntelopeIO/seperate_prod_fin
Browse files Browse the repository at this point in the history
Integration test for configuration where producer and finalizer nodes are separate
  • Loading branch information
linh2931 authored Apr 28, 2024
2 parents 70e4380 + 9666fd3 commit a7a555b
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 6 deletions.
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/keosd_auto_launch_test.py ${CMAKE_CUR
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/db_modes_test.sh ${CMAKE_CURRENT_BINARY_DIR}/db_modes_test.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/prod_preactivation_test.py ${CMAKE_CURRENT_BINARY_DIR}/prod_preactivation_test.py COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/release-build.sh ${CMAKE_CURRENT_BINARY_DIR}/release-build.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/separate_prod_fin_test_shape.json ${CMAKE_CURRENT_BINARY_DIR}/separate_prod_fin_test_shape.json COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/separate_prod_fin_test.py ${CMAKE_CURRENT_BINARY_DIR}/separate_prod_fin_test.py COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/snapshot_in_svnn_transition_test.py ${CMAKE_CURRENT_BINARY_DIR}/snapshot_in_svnn_transition_test.py COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-label.sh ${CMAKE_CURRENT_BINARY_DIR}/version-label.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/full-version-label.sh ${CMAKE_CURRENT_BINARY_DIR}/full-version-label.sh COPYONLY)
Expand Down Expand Up @@ -168,6 +170,8 @@ set_property(TEST p2p_dawn515_test PROPERTY LABELS nonparallelizable_tests)

add_test(NAME producer-preactivate-feature-test COMMAND tests/prod_preactivation_test.py ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST producer-preactivate-feature-test PROPERTY LABELS nonparallelizable_tests)
add_test(NAME separate_prod_fin_test COMMAND tests/separate_prod_fin_test.py ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST separate_prod_fin_test PROPERTY LABELS nonparallelizable_tests)
add_test(NAME snapshot_in_svnn_transition_test COMMAND tests/snapshot_in_svnn_transition_test.py ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST snapshot_in_svnn_transition_test PROPERTY LABELS nonparallelizable_tests)
add_test(NAME nodeos_protocol_feature_test COMMAND tests/nodeos_protocol_feature_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
Expand Down
16 changes: 10 additions & 6 deletions tests/TestHarness/Cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def launch(self, pnodes=1, unstartedNodes=0, totalNodes=1, prodCount=21, topo="m
totalProducers=None, sharedProducers=0, extraNodeosArgs="", specificExtraNodeosArgs=None, specificNodeosInstances=None, onlySetProds=False,
pfSetupPolicy=PFSetupPolicy.FULL, alternateVersionLabelsFile=None, associatedNodeLabels=None, loadSystemContract=True,
activateIF=False, biosFinalizer=True,
signatureProviderForNonProducer=False,
nodeosLogPath=Path(Utils.TestLogRoot) / Path(f'{Path(sys.argv[0]).stem}{os.getpid()}'), genesisPath=None,
maximumP2pPerHost=0, maximumClients=25, prodsEnableTraceApi=True):
"""Launch cluster.
Expand All @@ -191,6 +192,7 @@ def launch(self, pnodes=1, unstartedNodes=0, totalNodes=1, prodCount=21, topo="m
loadSystemContract: indicate whether the eosio.system contract should be loaded
activateIF: Activate/enable instant-finality by setting finalizers
biosFinalizer: True if the biosNode should act as a finalizer
signatureProviderForNonProducer: Add signature provider for non-producer
genesisPath: set the path to a specific genesis.json to use
maximumP2pPerHost: Maximum number of client nodes from any single IP address. Defaults to totalNodes if not set.
maximumClients: Maximum number of clients from which connections are accepted, use 0 for no limit. Defaults to 25.
Expand Down Expand Up @@ -465,6 +467,8 @@ def connectGroup(group, producerNodes, bridgeNodes) :
if "--plugin eosio::history_api_plugin" in args:
argsArr.append("--is-nodeos-v2")
break
if signatureProviderForNonProducer:
argsArr.append("--signature-provider")

# Handle common case of specifying no block offset for older versions
if "v2" in self.nodeosVers or "v3" in self.nodeosVers or "v4" in self.nodeosVers:
Expand Down Expand Up @@ -525,7 +529,7 @@ def connectGroup(group, producerNodes, bridgeNodes) :
return True

Utils.Print("Bootstrap cluster.")
if not self.bootstrap(launcher, self.biosNode, self.startedNodesCount, prodCount + sharedProducers, totalProducers, pfSetupPolicy, onlyBios, onlySetProds, loadSystemContract, activateIF, biosFinalizer):
if not self.bootstrap(launcher, self.biosNode, self.startedNodesCount, prodCount + sharedProducers, totalProducers, pfSetupPolicy, onlyBios, onlySetProds, loadSystemContract, activateIF, biosFinalizer, signatureProviderForNonProducer):
Utils.Print("ERROR: Bootstrap failed.")
return False

Expand Down Expand Up @@ -997,13 +1001,13 @@ def parseClusterKeys(totalNodes):
Utils.Print(f'Found {len(producerKeys)} producer keys')
return producerKeys

def activateInstantFinality(self, biosFinalizer=True, waitForFinalization=True):
def activateInstantFinality(self, biosFinalizer=True, waitForFinalization=True, signatureProviderForNonProducer=False):
# call setfinalizer
numFins = 0
for n in (self.nodes + [self.biosNode]):
if not n or not n.keys or not n.keys[0].blspubkey:
continue
if not n.isProducer:
if not signatureProviderForNonProducer and not n.isProducer:
continue
if n.nodeId == 'bios' and not biosFinalizer:
continue
Expand All @@ -1021,7 +1025,7 @@ def activateInstantFinality(self, biosFinalizer=True, waitForFinalization=True):
for n in (self.nodes + [self.biosNode]):
if not n or not n.keys or not n.keys[0].blspubkey:
continue
if not n.isProducer:
if not signatureProviderForNonProducer and not n.isProducer:
continue
if n.nodeId == 'bios' and not biosFinalizer:
continue
Expand Down Expand Up @@ -1050,7 +1054,7 @@ def activateInstantFinality(self, biosFinalizer=True, waitForFinalization=True):
return None, transId
return True, transId

def bootstrap(self, launcher, biosNode, totalNodes, prodCount, totalProducers, pfSetupPolicy, onlyBios=False, onlySetProds=False, loadSystemContract=True, activateIF=False, biosFinalizer=True):
def bootstrap(self, launcher, biosNode, totalNodes, prodCount, totalProducers, pfSetupPolicy, onlyBios=False, onlySetProds=False, loadSystemContract=True, activateIF=False, biosFinalizer=True, signatureProviderForNonProducer=False):
"""Create 'prodCount' init accounts and deposits 10000000000 SYS in each. If prodCount is -1 will initialize all possible producers.
Ensure nodes are inter-connected prior to this call. One way to validate this will be to check if every node has block 1."""

Expand Down Expand Up @@ -1114,7 +1118,7 @@ def bootstrap(self, launcher, biosNode, totalNodes, prodCount, totalProducers,
return None

if activateIF:
success, transId = self.activateInstantFinality(biosFinalizer=biosFinalizer)
success, transId = self.activateInstantFinality(biosFinalizer=biosFinalizer, signatureProviderForNonProducer=signatureProviderForNonProducer)
if not success:
Utils.Print("ERROR: Activate instant finality failed")
return None
Expand Down
5 changes: 5 additions & 0 deletions tests/TestHarness/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def comma_separated(string):
cfg.add_argument('--logging-level', type=fc_log_level, help='Provide the "level" value to use in the logging.json file')
cfg.add_argument('--logging-level-map', type=json.loads, help='JSON string of a logging level dictionary to use in the logging.json file for specific nodes, matching based on node number. Ex: {"bios":"off","00":"info"}')
cfg.add_argument('--is-nodeos-v2', action='store_true', help='Toggles old nodeos compatibility', default=False)
cfg.add_argument('--signature-provider', action='store_true', help='add signature provider (BLS key pair) for non-producers', default=False)
r = parser.parse_args(args)
if r.launch != 'none' and r.topology_filename:
Utils.Print('Output file specified--overriding launch to "none"')
Expand Down Expand Up @@ -523,6 +524,10 @@ def construct_command_line(self, instance: nodeDefinition):
eosdcmd.extend(producer_names)
else:
a(a(eosdcmd, '--transaction-retry-max-storage-size-gb'), '100')
if self.args.signature_provider:
finalizer_keys = list(sum([('--signature-provider', f'{key.blspubkey}=KEY:{key.blsprivkey}') for key in instance.keys if key.blspubkey is not None], ()))
if finalizer_keys:
eosdcmd.extend(finalizer_keys)
a(a(eosdcmd, '--plugin'), 'eosio::net_plugin')
a(a(eosdcmd, '--plugin'), 'eosio::chain_api_plugin')

Expand Down
80 changes: 80 additions & 0 deletions tests/separate_prod_fin_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env python3

from TestHarness import Cluster, TestHelper, Utils, WalletMgr
from TestHarness.TestHelper import AppArgs

###############################################################
# separate_prod_fin_test
#
# Test producer nodes and finalizer nodes which are separate. Configure 2 producer nodes and
# 3 non-producer nodes; each of them has a finalizer key. Since threshold is 4,
# if LIB advances, it implies at least 2 non-producer finalizer participates in
# the finalization process.
#
###############################################################


Print=Utils.Print
errorExit=Utils.errorExit

appArgs = AppArgs()
args=TestHelper.parse_args({"-d","--keep-logs","--dump-error-details","-v","--leave-running","--unshared"},
applicationSpecificArgs=appArgs)
pnodes=2 # producer node
delay=args.d
debug=args.v
total_nodes=pnodes+3 # 3 non-producer nodes
dumpErrorDetails=args.dump_error_details

Utils.Debug=debug
testSuccessful=False

cluster=Cluster(unshared=args.unshared, keepRunning=args.leave_running, keepLogs=args.keep_logs)
walletMgr=WalletMgr(True, keepRunning=args.leave_running, keepLogs=args.keep_logs)

try:
TestHelper.printSystemInfo("BEGIN")

cluster.setWalletMgr(walletMgr)

Print(f'producing nodes: {pnodes}, delay between nodes launch: {delay} second{"s" if delay != 1 else ""}')

Print("Stand up cluster")
# For now do not load system contract as it does not support setfinalizer
# separate_prod_fin_test_shape.json defines 2 producer nodes each has 1
# producer and 3 non-producer nodes
if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, totalProducers=pnodes,
topo="./tests/separate_prod_fin_test_shape.json", delay=delay,
activateIF=True, signatureProviderForNonProducer=True) is False:
errorExit("Failed to stand up eos cluster.")

assert cluster.biosNode.getInfo(exitOnError=True)["head_block_producer"] != "eosio", "launch should have waited for production to change"

cluster.biosNode.waitForHeadToAdvance()

Print("Wait for LIB advancing")
assert cluster.biosNode.waitForLibToAdvance(), "Lib should advance after instant finality activated"
assert cluster.biosNode.waitForProducer("defproducera"), "Did not see defproducera"
assert cluster.biosNode.waitForHeadToAdvance(blocksToAdvance=13), "Head did not advance 13 blocks to next producer"
assert cluster.biosNode.waitForLibToAdvance(), "Lib stopped advancing on biosNode"
assert cluster.getNode(1).waitForLibToAdvance(), "Lib stopped advancing on Node 1"

info = cluster.biosNode.getInfo(exitOnError=True)
assert (info["head_block_num"] - info["last_irreversible_block_num"]) < 9, "Instant finality enabled LIB diff should be small"

# LIB has advanced, which indicate at least 2 of non-producer finalizers have voted.
# Double check that's indeed the case in qc_extension
info = cluster.getNode(1).getInfo(exitOnError=True)
block_num = info["last_irreversible_block_num"]
block = cluster.getNode(1).getBlock(block_num)
qc_ext = block["qc_extension"]
Print(f'{qc_ext}')
# "11111" is the representation of a bitset showing which finalizers have voted (we have five total finalizers)
assert qc_ext["qc"]["data"]["strong_votes"] == "11111", 'Not all finalizers voted'

testSuccessful=True
finally:
TestHelper.shutdown(cluster, walletMgr, testSuccessful=testSuccessful, dumpErrorDetails=dumpErrorDetails)

exitCode = 0 if testSuccessful else 1
exit(exitCode)
137 changes: 137 additions & 0 deletions tests/separate_prod_fin_test_shape.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"name": "testnet_",
"ssh_helper": {
"ssh_cmd": "/usr/bin/ssh",
"scp_cmd": "/usr/bin/scp",
"ssh_identity": "",
"ssh_args": ""
},
"nodes": {
"bios":{
"name": "bios",
"keys": [
{
"privkey":"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3",
"pubkey":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
}
],
"peers": [],
"producers": [
"eosio"
],
"dont_start": false
},
"testnet_00":{
"name": "testnet_00",
"keys": [
{
"privkey":"5Jf4sTk7vwX1MYpLJ2eQFanVvKYXFqGBrCyANPukuP2BJ5WAAKZ",
"pubkey":"EOS58B33q9S7oNkgeFfcoW3VJYu4obfDiqn5RHGE2ige6jVjUhymR",
"blspubkey":"PUB_BLS_Uf3df_EqPpR31ZkenPtwgGUtd69cahyuY2lc9jPwEta7Q6t7REV-Hd35hUIDel4N7pQdCGZdnVZzs_UmJghEjGhVHN1QVVAQjOca8Fs10D_jqTiUzffzqyBAvTHyZtoEEPyXkg",
"blsprivkey":"PVT_BLS_t2sZsoDWTQFIKg75bhJn8pBA0iDYcWyn3HlEfKIzTzKozgKO",
"blspop":"SIG_BLS_TnwBY4dpG54mCue3ZXwjCio0AIdWYwFdz5ipLdnXlg64FkYkhMUtkOdQIs1IYbMWOXlD6OnCP6jcCWi5VziWKNbLfMX64SdIkNPKOHrfE_8fBfIk9Onj7GbWx3q0LbYP7NfJQk1mk-gOjz1G3elZDDHt367YUgzYDKhtl1FSkfZzDRzDsCSei7H1MjLi_e0RVdUfgqAznGaq2Yss6gY-HzwzgHU4y-SNQpzdCuDlLEEIjkHq8fXuMiPWT2Dlt8kOML0uqg"
}
],
"peers": [
"bios",
"testnet_01",
"testnet_02",
"testnet_03",
"testnet_04"
],
"producers": [
"defproducera"
],
"dont_start": false
},
"testnet_01":{
"name": "testnet_01",
"keys": [
{
"privkey":"5HviUPkTEtvF2B1nm8aZUnjma2TzgpKRjuXjwHyy3FME4xDbkZF",
"pubkey":"EOS5CbcTDgbks2ptTxvyCbT9HFbzX7PDHUY2wN4DDnVBhhQr2ZNDE",
"blspubkey":"PUB_BLS_Y8ndNvnrEpnzJcNUg49ncWDiDGRgR7WUmRRDR9yMURoS6zF14sPnbb-DsTGp0cEM628a4CmG6KXMhPJMqGZvb7RM_MGIwgbEhVaENL8rXeYLOuFDS375KHFgXxs2P5sZuaN7aA",
"blsprivkey":"PVT_BLS_A1Mifu5xyaxiveyjnZ-qN2zOt-5_KLMpjTrDI9udcQNV1NBR",
"blspop":"SIG_BLS_7D0OUU1h7E0AKkAmqV4v3Ot9oSPWJBOss4yDejr2x1g5G31cSSAYIAtqZOYC-ioNzddY7zkvTcbhKgBzv5a-G1HmV1pOCXXPJ5TL0iqU8Ks5abeEWCdhArGATmRQiSMYNcj9rMQcm3H6Z0pOlOdbDdt8Cg-SY_H4jEGmAY2ZqudAH_U8gS19aydJU-2uQq0SPIr2Okl-WNbc-q3NVQw6Y0sAHAwN4BOIHup2MJyDDDIbpSEkBchRp3zna1XJf6oBuUzpqQ"
}
],
"peers": [
"bios",
"testnet_00",
"testnet_02",
"testnet_03",
"testnet_04"
],
"producers": [
"defproducerb"
],
"dont_start": false
},
"testnet_02":{
"name": "testnet_02",
"keys": [
{
"privkey":"5KkQbdxFHr8Pg1N3DEMDdU7emFgUTwQvh99FDJrodFhUbbsAtQT",
"pubkey":"EOS6Tkpf8kcDfa32WA9B4nTcEJ64ZdDMSNioDcaL6rzdMwnpzaWJB",
"blspubkey":"PUB_BLS_Wf_O_QeyVhekDXS5q3qBxTyj_qxSrX_uiCY4z8ClpW0X2jrAVgAVHOQ9IR2H40QTWveD8QIGhhSbmSFPa0zFbs5k3yfnjfuuwpA7T1O13_LSdtxT19ehYiE4chZX6SUMJ09JFA",
"blsprivkey":"PVT_BLS_1ZLWim0k80ssXswSZp1T3ydHO9U3gLnKKlEBIDy8927XDLLj",
"blspop":"SIG_BLS_EL09aI3w-qCgarLM2Z5-T6sisSHBN0J4vMZxtGQklkOcAxgnCaPPXe0roxY4W0gVe2y6T01YrklmT_qZu2tAwqiNrVJcScY8QKvRSeczGBBab1MgnHvaAOuf6bA4JPAELIu2iPWfsS6-oLyLbNP5xtZpMXPHu3yaSJssXNOb5rcVs1KXaIUEagJeAlBBQEcKmFWfeAsJ_R8JDw4i9gSNmROzUjm6LVBpvB7vrnPDPFRA0BQ19H4FED6PtuFPShwJGVz4dg"
}
],
"peers": [
"bios",
"testnet_00",
"testnet_01",
"testnet_02",
"testnet_04"
],
"producers": [
],
"dont_start": false
},
"testnet_03":{
"name": "testnet_03",
"keys": [
{
"privkey":"5JxTJJegQBpEL1p77TzkN1ompMB9gDwAfjM9chPzFCB4chxmwrE",
"pubkey":"EOS52ntDHqA2qj4xVo7KmxdezMRhvvBqpZBuKYJCsgihisxmywpAx",
"blspubkey":"PUB_BLS_C-FprIiry6X-8dlLYH7xUAhIuKXBQv56zJPgtcdmKeHf8AAy750eRrOYBtKG0-QEIN5l_yl9dTLvAYmOios6Q5t3ybWBUVVQ2WWcbZLVxzwBftLwYvo1zPXH7LHEE_sAgP1i7g",
"blsprivkey":"PVT_BLS_ubElmjajfsYP_9HRSpmV-Fi_IPWKTyJS4XFSWrU8ezMZ_mL_",
"blspop":"SIG_BLS_k3wrhVl2GUG_lGsPr9io-zoamPw7eiaxMDExk-yOqcpXtu0zALHoUWJRh0WOerAS1-_RQNhbi4q-BWO9IbiNWRKP9CYIhNIL6ochGHHy4aBmZ-IzEjfBrDt7inDtFTYY0Gl372e5OqPXAwi6J3GeHipXuzAiw7SV8XdWFefthxId4meKX6vw5_RWx4XQ4ScRYoCG7UQtIZkQPEsu1SfJGL6z-cfTTSq-naKbzp0QQYfqtQkFfmL7qQUH1iohnb0HbTbRbQ"
}
],
"peers": [
"bios",
"testnet_00",
"testnet_01",
"testnet_02",
"testnet_04"
],
"producers": [
],
"dont_start": false
},
"testnet_04":{
"name": "testnet_04",
"keys": [
{
"privkey":"5K3h9XiAmrx9EuqD8CRxHgQwEVDaWpqrhrnpdvwHtVzwJFMhNmE",
"pubkey":"EOS7K5pQCk22ojetRdyumrqp6nJX6eiQiTWWcGkZAMGhoBxgcsxhK",
"blspubkey":"PUB_BLS_kGOCEX1MM5Xl928OOvGLyNo3_GpV8av1HnoaCEGOD8bAu3MDvazu0gCZGA1G7msTh1ZTPMEMVdXMuRVS0tv_9bW9Ohz9XvgtjgbPpxxc_NaeENkGg4uDBOro0Rk8DCEW4ToLKA",
"blsprivkey":"PVT_BLS_EnQXObGKvYqfubrKjxpCqNkHeLlkQg7LERjDGm1RKjgyFZnk",
"blspop":"SIG_BLS_bXrzPVc-ahxOCWrcl-iWIMuS8ego54iz7vi38A8h_ViqtxklH9O3A2z0eiw5j40M08ejiTm7JbCY_GOwulv1oXb9SaLYQkCTZjzCVssDkghLBRTVCZW2oJmU9WbZXikNw6nkygTs5sUTtCda2a_M5jqY_Rw92_NWmbolgBNkFvMcAgSHexdETA-b7QgJX_oYBWkyP0Pt8LzO6bJueZSjH8wZ8VuPc9o8taY85mt_qgdOTbXVBG2m5ud0eAUps2UHAHt-Ig"
}
],
"peers": [
"bios",
"testnet_00",
"testnet_01",
"testnet_02",
"testnet_03"
],
"producers": [
],
"dont_start": false
}
}
}

0 comments on commit a7a555b

Please sign in to comment.