33import copy
44import signal
55
6- from TestHarness import Cluster , TestHelper , Utils , WalletMgr , createAccountKeys
6+ from TestHarness import Cluster , TestHelper , Utils , WalletMgr , CORE_SYMBOL , createAccountKeys
77
88###############################################################
99# auto_bp_gossip_peering_test
1010#
11- # This test sets up a cluster with 21 producers nodeos, each nodeos is configured with only one producer and only
11+ # This test sets up a cluster with 21 producers nodeos, each nodeos is configured with only one producer and only
1212# connects to the bios node. Moreover, each producer nodeos is also configured with a p2p-bp-gossip-endpoint so that
1313# each one can automatically establish p2p connections to other bps. Test verifies connections are established when
1414# producer schedule is active.
1515#
16+ # Test then changes the producer schedule and verifies that connections change appropriately.
17+ # Also verifies manual connections are maintained and that non-producers disconnect from producers when they are no
18+ # longer in the schedule.
19+ #
1620###############################################################
1721
1822Print = Utils .Print
@@ -64,6 +68,14 @@ def getHostName(nodeId):
6468 accounts = createAccountKeys (21 )
6569 if accounts is None :
6670 Utils .errorExit ("FAILURE - create keys" )
71+ voteAccounts = createAccountKeys (5 )
72+ if voteAccounts is None :
73+ Utils .errorExit ("FAILURE - create keys" )
74+ voteAccounts [0 ].name = "tester111111"
75+ voteAccounts [1 ].name = "tester222222"
76+ voteAccounts [2 ].name = "tester333333"
77+ voteAccounts [3 ].name = "tester444444"
78+ voteAccounts [4 ].name = "tester555555"
6779
6880 if walletMgr .launch () is False :
6981 errorExit ("Failed to stand up keosd." )
@@ -96,26 +108,45 @@ def getHostName(nodeId):
96108 Print ("Creating wallet \" %s\" " % (testWalletName ))
97109 walletAccounts = copy .deepcopy (cluster .defProducerAccounts )
98110 testWallet = walletMgr .create (testWalletName , walletAccounts .values ())
111+ walletMgr .importKeys (voteAccounts , testWallet )
99112 all_acc = accounts + list ( cluster .defProducerAccounts .values () )
100113 for account in all_acc :
101114 Print ("Importing keys for account %s into wallet %s." % (account .name , testWallet .name ))
102115 if not walletMgr .importKey (account , testWallet ):
103116 errorExit ("Failed to import key for account %s" % (account .name ))
104117
118+ for i in range (0 , producerNodes ):
119+ node = cluster .getNode (i )
120+ node .producers = Cluster .parseProducers (i )
121+ for prod in node .producers :
122+ trans = cluster .biosNode .regproducer (cluster .defProducerAccounts [prod ], "http::/mysite.com" , 0 ,
123+ waitForTransBlock = False , silentErrors = False )
124+ Print ("Setup vote accounts so they can vote" )
125+ # create accounts via eosio as otherwise a bid is needed
126+ for account in voteAccounts :
127+ Print ("Create new account %s via %s" % (account .name , cluster .eosioAccount .name ))
128+ trans = cluster .biosNode .createInitializeAccount (account , cluster .eosioAccount , stakedDeposit = 0 , waitForTransBlock = False , stakeNet = 1000 , stakeCPU = 1000 , buyRAM = 1000 , exitOnError = True )
129+ cluster .biosNode .waitForTransactionInBlock (trans ['transaction_id' ])
130+ transferAmount = "100000000.0000 {0}" .format (CORE_SYMBOL )
131+ Print ("Transfer funds %s from account %s to %s" % (transferAmount , cluster .eosioAccount .name , account .name ))
132+ trans = cluster .biosNode .transferFunds (cluster .eosioAccount , account , transferAmount , "test transfer" , waitForTransBlock = False )
133+ cluster .biosNode .waitForTransactionInBlock (trans ['transaction_id' ])
134+ trans = cluster .biosNode .delegatebw (account , 20000000.0000 , 20000000.0000 , waitForTransBlock = False , exitOnError = False )
135+
136+ Print ("regpeerkey for all the producers" )
105137 for nodeId in range (0 , producerNodes ):
106138 producer_name = "defproducer" + chr (ord ('a' ) + nodeId )
107139 a = accounts [nodeId ]
108140 node = cluster .getNode (nodeId )
109141
110142 success , trans = cluster .biosNode .pushMessage ('eosio' , 'regpeerkey' , f'{{"proposer_finalizer_name":"{ producer_name } ","key":"{ a .activePublicKey } "}}' , f'-p { producer_name } @active' )
111143 assert (success )
112-
113144 # wait for regpeerkey to be final
114145 for nodeId in range (0 , producerNodes ):
115146 Utils .Print ("Wait for last regpeerkey to be final on " , nodeId )
116147 cluster .getNode (nodeId ).waitForTransFinalization (trans ['transaction_id' ])
117148
118- # relaunch with p2p-bp-gossip-endpoint
149+ Print ( " relaunch with p2p-bp-gossip-endpoint to enable BP gossip" )
119150 for nodeId in range (0 , producerNodes ):
120151 Utils .Print (f"Relaunch node { nodeId } with p2p-bp-gossip-endpoint" )
121152 node = cluster .getNode (nodeId )
@@ -125,64 +156,98 @@ def getHostName(nodeId):
125156 if not node .relaunch (chainArg = f" --enable-stale-production --p2p-bp-gossip-endpoint { producer_name } ,{ server_address } ,127.0.0.1" ):
126157 errorExit (f"Failed to relaunch node { nodeId } " )
127158
128- # give time for messages to be gossiped around
159+ Print ( "Wait for messages to be gossiped" )
129160 cluster .getNode (producerNodes - 1 ).waitForHeadToAdvance (blocksToAdvance = 60 )
130161 blockNum = cluster .getNode (0 ).getBlockNum ()
131162 for nodeId in range (0 , producerNodes ):
132163 Utils .Print (f"Wait for block ${ blockNum } on node " , nodeId )
133164 cluster .getNode (nodeId ).waitForBlock (blockNum )
134165
135- # retrieve the producer stable producer schedule
136- scheduled_producers = []
137- schedule = cluster .nodes [0 ].processUrllibRequest ("chain" , "get_producer_schedule" )
138- for prod in schedule ["payload" ]["active" ]["producers" ]:
139- scheduled_producers .append (prod ["producer_name" ])
140- scheduled_producers .sort ()
141-
142- connection_failure = False
143- for nodeId in range (0 , producerNodes ):
144- # retrieve the connections in each node and check if each connects to the other bps in the schedule
145- connections = cluster .nodes [nodeId ].processUrllibRequest ("net" , "connections" )
146- if Utils .Debug : Utils .Print (f"v1/net/connections: { connections } " )
147- bp_peers = cluster .nodes [nodeId ].processUrllibRequest ("net" , "bp_gossip_peers" )
148- if Utils .Debug : Utils .Print (f"v1/net/bp_gossip_peers: { bp_peers } " )
149- peers = []
150- for conn in connections ["payload" ]:
151- if conn ["is_socket_open" ] is False :
152- continue
153- peer_addr = conn ["peer" ]
154- if len (peer_addr ) == 0 :
155- if len (conn ["last_handshake" ]["p2p_address" ]) == 0 :
166+ def verifyGossipConnections (scheduled_producers ):
167+ assert (len (scheduled_producers ) > 0 )
168+ scheduled_producers .sort ()
169+ connection_failure = False
170+ for nodeId in range (0 , producerNodes ):
171+ name = "defproducer" + chr (ord ('a' ) + nodeId )
172+ if name not in scheduled_producers :
173+ break
174+ # retrieve the connections in each node and check if each connects to the other bps in the schedule
175+ connections = cluster .nodes [nodeId ].processUrllibRequest ("net" , "connections" )
176+ if Utils .Debug : Utils .Print (f"v1/net/connections: { connections } " )
177+ bp_peers = cluster .nodes [nodeId ].processUrllibRequest ("net" , "bp_gossip_peers" )
178+ if Utils .Debug : Utils .Print (f"v1/net/bp_gossip_peers: { bp_peers } " )
179+ peers = []
180+ for conn in connections ["payload" ]:
181+ if conn ["is_socket_open" ] is False :
156182 continue
157- peer_addr = conn ["last_handshake" ]["p2p_address" ].split ()[0 ]
158- if peer_names [peer_addr ] != "bios" and peer_addr != getHostName (nodeId ):
159- if conn ["is_bp_peer" ]:
160- peers .append (peer_names [peer_addr ])
161-
162- if not peers :
163- Utils .Print (f"ERROR: found no connected peers for node { nodeId } " )
164- connection_failure = True
165- break
166- name = "defproducer" + chr (ord ('a' ) + nodeId )
167- peers .append (name ) # add ourselves so matches schedule_producers
168- peers = list (set (peers ))
169- peers .sort ()
170- if peers != scheduled_producers :
171- Utils .Print (f"ERROR: expect { name } has connections to { scheduled_producers } , got connections to { peers } " )
172- connection_failure = True
173- break
174- num_peers_found = 0
175- for p in bp_peers ["payload" ]:
176- if p ["producer_name" ] not in peers :
177- Utils .Print (f"ERROR: expect bp peer { p } in peer list" )
183+ peer_addr = conn ["peer" ]
184+ if len (peer_addr ) == 0 :
185+ if len (conn ["last_handshake" ]["p2p_address" ]) == 0 :
186+ continue
187+ peer_addr = conn ["last_handshake" ]["p2p_address" ].split ()[0 ]
188+ if peer_names [peer_addr ] != "bios" and peer_addr != getHostName (nodeId ):
189+ if conn ["is_bp_peer" ]:
190+ peers .append (peer_names [peer_addr ])
191+
192+ if not peers :
193+ Utils .Print (f"ERROR: found no connected peers for node { nodeId } " )
178194 connection_failure = True
179195 break
180- else :
181- num_peers_found += 1
196+ peers .append (name ) # add ourselves so matches schedule_producers
197+ peers = list (set (peers ))
198+ peers .sort ()
199+ if peers != scheduled_producers :
200+ Utils .Print (f"ERROR: expect { name } has connections to { scheduled_producers } , got connections to { peers } " )
201+ connection_failure = True
202+ break
203+ num_peers_found = 0
204+ for p in bp_peers ["payload" ]:
205+ if p ["producer_name" ] not in peers :
206+ Utils .Print (f"ERROR: expect bp peer { p } in peer list" )
207+ connection_failure = True
208+ break
209+ else :
210+ num_peers_found += 1
211+
212+ assert (num_peers_found == len (peers ))
213+ return not connection_failure
214+
215+ Print ("Verify gossip connections" )
216+ scheduled_producers = cluster .nodes [0 ].getProducerSchedule ()
217+ success = verifyGossipConnections (scheduled_producers )
218+ assert (success )
219+
220+ Print ("Manual connect node_03 defproducerd to node_04 defproducere" )
221+ cluster .nodes [3 ].processUrllibRequest ("net" , "connect" , payload = "localhost:9880" , exitOnError = True )
222+
223+ Print ("Set new producers b,h,m,r" )
224+ for account in voteAccounts :
225+ trans = cluster .biosNode .vote (account , ["defproducerb" , "defproducerh" , "defproducerm" , "defproducerr" ], silentErrors = False , exitOnError = True )
226+ cluster .biosNode .getNextCleanProductionCycle (trans )
227+
228+ Print ("Verify new gossip connections" )
229+ scheduled_producers = cluster .nodes [0 ].getProducerSchedule ()
230+ Print (f"Scheduled producers: { scheduled_producers } " )
231+ assert (len (scheduled_producers ) == 4 )
232+ assert ("defproducerb" in scheduled_producers and "defproducerh" in scheduled_producers and "defproducerm" in scheduled_producers and "defproducerr" in scheduled_producers )
233+ success = verifyGossipConnections (scheduled_producers )
234+ assert (success )
235+
236+ Print ("Verify manual connection still connected" )
237+ connections = cluster .nodes [3 ].processUrllibRequest ("net" , "connections" )
238+ if Utils .Debug : Utils .Print (f"v1/net/connections: { connections } " )
239+ found = []
240+ for conn in connections ["payload" ]:
241+ if conn ["is_socket_open" ] is False :
242+ continue
243+ peer_addr = conn ["peer" ]
244+ found .append (peer_names [peer_addr ])
182245
183- assert (num_peers_found == len (peers ))
246+ Print (f"Found connections of Node_03: { found } " )
247+ assert (len (found ) == 2 )
248+ assert ("bios" in found and "defproducere" in found )
184249
185- testSuccessful = not connection_failure
250+ testSuccessful = success
186251
187252finally :
188253 TestHelper .shutdown (
0 commit comments