Skip to content

Commit 4ecfe28

Browse files
authored
Merge pull request #5272 from stacks-network/chore/ci-fix-bind-ports
Bind ports should not use the same port numbers
2 parents 03b3599 + 3690ad9 commit 4ecfe28

File tree

3 files changed

+77
-70
lines changed

3 files changed

+77
-70
lines changed

testnet/stacks-node/src/tests/mod.rs

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@
1313
//
1414
// You should have received a copy of the GNU General Public License
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16-
use std::collections::HashMap;
16+
use std::collections::{HashMap, HashSet};
1717
use std::sync::atomic::AtomicU64;
18-
use std::sync::Arc;
18+
use std::sync::{Arc, Mutex};
1919

2020
use clarity::vm::costs::ExecutionCost;
2121
use clarity::vm::database::BurnStateDB;
2222
use clarity::vm::events::STXEventType;
2323
use clarity::vm::types::PrincipalData;
2424
use clarity::vm::{ClarityName, ClarityVersion, ContractName, Value};
2525
use lazy_static::lazy_static;
26-
use rand::RngCore;
26+
use rand::Rng;
2727
use stacks::chainstate::burn::ConsensusHash;
2828
use stacks::chainstate::stacks::db::StacksChainState;
2929
use stacks::chainstate::stacks::events::StacksTransactionEvent;
@@ -99,6 +99,34 @@ lazy_static! {
9999
);
100100
}
101101

102+
lazy_static! {
103+
static ref USED_PORTS: Mutex<HashSet<u16>> = Mutex::new(HashSet::new());
104+
}
105+
106+
/// Generate a random port number between 1024 and 65534 (inclusive) and insert it into the USED_PORTS set.
107+
/// Returns the generated port number.
108+
pub fn gen_random_port() -> u16 {
109+
let mut rng = rand::thread_rng();
110+
let range_len = (1024..u16::MAX).len();
111+
loop {
112+
assert!(
113+
USED_PORTS.lock().unwrap().len() < range_len,
114+
"No more available ports"
115+
);
116+
let port = rng.gen_range(1024..u16::MAX); // use a non-privileged port between 1024 and 65534
117+
if insert_new_port(port) {
118+
return port;
119+
}
120+
}
121+
}
122+
123+
// Add a port to the USED_PORTS set. This is used to ensure that we don't try to bind to the same port in tests
124+
// Returns true if the port was inserted, false if it was already in the set.
125+
pub fn insert_new_port(port: u16) -> bool {
126+
let mut ports = USED_PORTS.lock().unwrap();
127+
ports.insert(port)
128+
}
129+
102130
pub fn serialize_sign_sponsored_sig_tx_anchor_mode_version(
103131
payload: TransactionPayload,
104132
sender: &StacksPrivateKey,
@@ -294,14 +322,13 @@ pub fn new_test_conf() -> Config {
294322
// secretKey: "b1cf9cee5083f421c84d7cb53be5edf2801c3c78d63d53917aee0bdc8bd160ee01",
295323
// publicKey: "03e2ed46873d0db820e8c6001aabc082d72b5b900b53b7a1b9714fe7bde3037b81",
296324
// stacksAddress: "ST2VHM28V9E5QCRD6C73215KAPSBKQGPWTEE5CMQT"
297-
let mut rng = rand::thread_rng();
298-
let mut buf = [0u8; 8];
299-
rng.fill_bytes(&mut buf);
325+
let rpc_port = gen_random_port();
326+
let p2p_port = gen_random_port();
300327

301328
let mut conf = Config::default();
302329
conf.node.working_dir = format!(
303330
"/tmp/stacks-node-tests/integrations-neon/{}-{}",
304-
to_hex(&buf),
331+
to_hex(format!("{rpc_port}{p2p_port}").as_bytes()),
305332
get_epoch_time_secs()
306333
);
307334
conf.node.seed =
@@ -313,19 +340,17 @@ pub fn new_test_conf() -> Config {
313340

314341
conf.burnchain.epochs = Some(StacksEpoch::all(0, 0, 0));
315342

316-
let rpc_port = u16::from_be_bytes(buf[0..2].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
317-
let p2p_port = u16::from_be_bytes(buf[2..4].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
318-
319343
let localhost = "127.0.0.1";
320-
conf.node.rpc_bind = format!("{}:{}", localhost, rpc_port);
321-
conf.node.p2p_bind = format!("{}:{}", localhost, p2p_port);
322-
conf.node.data_url = format!("http://{}:{}", localhost, rpc_port);
323-
conf.node.p2p_address = format!("{}:{}", localhost, p2p_port);
344+
conf.node.rpc_bind = format!("{localhost}:{rpc_port}");
345+
conf.node.p2p_bind = format!("{localhost}:{p2p_port}");
346+
conf.node.data_url = format!("http://{localhost}:{rpc_port}");
347+
conf.node.p2p_address = format!("{localhost}:{p2p_port}");
324348
conf
325349
}
326350

327351
/// Randomly change the config's network ports to new ports.
328352
pub fn set_random_binds(config: &mut Config) {
353+
// Just in case prior config was not created with `new_test_conf`, we need to add the prior generated ports
329354
let prior_rpc_port: u16 = config
330355
.node
331356
.rpc_bind
@@ -342,16 +367,10 @@ pub fn set_random_binds(config: &mut Config) {
342367
.unwrap()
343368
.parse()
344369
.unwrap();
345-
let (rpc_port, p2p_port) = loop {
346-
let mut rng = rand::thread_rng();
347-
let mut buf = [0u8; 8];
348-
rng.fill_bytes(&mut buf);
349-
let rpc_port = u16::from_be_bytes(buf[0..2].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
350-
let p2p_port = u16::from_be_bytes(buf[2..4].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
351-
if rpc_port != prior_rpc_port && p2p_port != prior_p2p_port {
352-
break (rpc_port, p2p_port);
353-
}
354-
};
370+
insert_new_port(prior_rpc_port);
371+
insert_new_port(prior_p2p_port);
372+
let rpc_port = gen_random_port();
373+
let p2p_port = gen_random_port();
355374
let localhost = "127.0.0.1";
356375
config.node.rpc_bind = format!("{}:{}", localhost, rpc_port);
357376
config.node.p2p_bind = format!("{}:{}", localhost, p2p_port);

testnet/stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use http_types::headers::AUTHORIZATION;
2929
use lazy_static::lazy_static;
3030
use libsigner::v0::messages::SignerMessage as SignerMessageV0;
3131
use libsigner::{SignerSession, StackerDBSession};
32-
use rand::RngCore;
3332
use stacks::burnchains::{MagicBytes, Txid};
3433
use stacks::chainstate::burn::db::sortdb::SortitionDB;
3534
use stacks::chainstate::burn::operations::{
@@ -105,8 +104,8 @@ use crate::tests::neon_integrations::{
105104
test_observer, wait_for_runloop,
106105
};
107106
use crate::tests::{
108-
get_chain_info, make_contract_publish, make_contract_publish_versioned, make_stacks_transfer,
109-
to_addr,
107+
gen_random_port, get_chain_info, make_contract_publish, make_contract_publish_versioned,
108+
make_stacks_transfer, to_addr,
110109
};
111110
use crate::{tests, BitcoinRegtestController, BurnchainController, Config, ConfigFile, Keychain};
112111

@@ -3459,18 +3458,14 @@ fn follower_bootup() {
34593458
follower_conf.node.seed = vec![0x01; 32];
34603459
follower_conf.node.local_peer_seed = vec![0x02; 32];
34613460

3462-
let mut rng = rand::thread_rng();
3463-
let mut buf = [0u8; 8];
3464-
rng.fill_bytes(&mut buf);
3465-
3466-
let rpc_port = u16::from_be_bytes(buf[0..2].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
3467-
let p2p_port = u16::from_be_bytes(buf[2..4].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
3461+
let rpc_port = gen_random_port();
3462+
let p2p_port = gen_random_port();
34683463

34693464
let localhost = "127.0.0.1";
3470-
follower_conf.node.rpc_bind = format!("{}:{}", &localhost, rpc_port);
3471-
follower_conf.node.p2p_bind = format!("{}:{}", &localhost, p2p_port);
3472-
follower_conf.node.data_url = format!("http://{}:{}", &localhost, rpc_port);
3473-
follower_conf.node.p2p_address = format!("{}:{}", &localhost, p2p_port);
3465+
follower_conf.node.rpc_bind = format!("{localhost}:{rpc_port}");
3466+
follower_conf.node.p2p_bind = format!("{localhost}:{p2p_port}");
3467+
follower_conf.node.data_url = format!("http://{localhost}:{rpc_port}");
3468+
follower_conf.node.p2p_address = format!("{localhost}:{p2p_port}");
34743469
follower_conf.node.pox_sync_sample_secs = 30;
34753470

34763471
let node_info = get_chain_info(&naka_conf);
@@ -3813,18 +3808,14 @@ fn follower_bootup_across_multiple_cycles() {
38133808
follower_conf.node.local_peer_seed = vec![0x02; 32];
38143809
follower_conf.node.miner = false;
38153810

3816-
let mut rng = rand::thread_rng();
3817-
let mut buf = [0u8; 8];
3818-
rng.fill_bytes(&mut buf);
3819-
3820-
let rpc_port = u16::from_be_bytes(buf[0..2].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
3821-
let p2p_port = u16::from_be_bytes(buf[2..4].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
3811+
let rpc_port = gen_random_port();
3812+
let p2p_port = gen_random_port();
38223813

38233814
let localhost = "127.0.0.1";
3824-
follower_conf.node.rpc_bind = format!("{}:{}", &localhost, rpc_port);
3825-
follower_conf.node.p2p_bind = format!("{}:{}", &localhost, p2p_port);
3826-
follower_conf.node.data_url = format!("http://{}:{}", &localhost, rpc_port);
3827-
follower_conf.node.p2p_address = format!("{}:{}", &localhost, p2p_port);
3815+
follower_conf.node.rpc_bind = format!("{localhost}:{rpc_port}");
3816+
follower_conf.node.p2p_bind = format!("{localhost}:{p2p_port}");
3817+
follower_conf.node.data_url = format!("http://{localhost}:{rpc_port}");
3818+
follower_conf.node.p2p_address = format!("{localhost}:{p2p_port}");
38283819
follower_conf.node.pox_sync_sample_secs = 30;
38293820

38303821
let node_info = get_chain_info(&naka_conf);

testnet/stacks-node/src/tests/neon_integrations.rs

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use clarity::vm::costs::ExecutionCost;
1212
use clarity::vm::types::serialization::SerializationError;
1313
use clarity::vm::types::PrincipalData;
1414
use clarity::vm::{ClarityName, ClarityVersion, ContractName, Value, MAX_CALL_STACK_DEPTH};
15-
use rand::{Rng, RngCore};
15+
use rand::Rng;
1616
use rusqlite::params;
1717
use serde::Deserialize;
1818
use serde_json::json;
@@ -89,6 +89,7 @@ use crate::neon_node::RelayerThread;
8989
use crate::operations::BurnchainOpSigner;
9090
use crate::stacks_common::types::PrivateKey;
9191
use crate::syncctl::PoxSyncWatchdogComms;
92+
use crate::tests::gen_random_port;
9293
use crate::tests::nakamoto_integrations::{get_key_for_cycle, wait_for};
9394
use crate::util::hash::{MerkleTree, Sha512Trunc256Sum};
9495
use crate::util::secp256k1::MessageSignature;
@@ -986,7 +987,9 @@ fn bitcoind_integration_test() {
986987
}
987988

988989
let (mut conf, miner_account) = neon_integration_test_conf();
989-
let prom_bind = format!("{}:{}", "127.0.0.1", 6000);
990+
let prom_port = gen_random_port();
991+
let localhost = "127.0.0.1";
992+
let prom_bind = format!("{localhost}:{prom_port}");
990993
conf.node.prometheus_bind = Some(prom_bind.clone());
991994

992995
conf.burnchain.max_rbf = 1000000;
@@ -12466,18 +12469,15 @@ fn bitcoin_reorg_flap_with_follower() {
1246612469
follower_conf.node.seed = vec![0x01; 32];
1246712470
follower_conf.node.local_peer_seed = vec![0x02; 32];
1246812471

12469-
let mut rng = rand::thread_rng();
12470-
let mut buf = [0u8; 8];
12471-
rng.fill_bytes(&mut buf);
12472-
12473-
let rpc_port = u16::from_be_bytes(buf[0..2].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
12474-
let p2p_port = u16::from_be_bytes(buf[2..4].try_into().unwrap()).saturating_add(1025) - 1; // use a non-privileged port between 1024 and 65534
12472+
let rpc_port = gen_random_port();
12473+
let p2p_port = gen_random_port();
1247512474

1247612475
let localhost = "127.0.0.1";
12477-
follower_conf.node.rpc_bind = format!("{}:{}", &localhost, rpc_port);
12478-
follower_conf.node.p2p_bind = format!("{}:{}", &localhost, p2p_port);
12479-
follower_conf.node.data_url = format!("http://{}:{}", &localhost, rpc_port);
12480-
follower_conf.node.p2p_address = format!("{}:{}", &localhost, p2p_port);
12476+
follower_conf.node.rpc_bind = format!("{localhost}:{rpc_port}");
12477+
follower_conf.node.p2p_bind = format!("{localhost}:{p2p_port}");
12478+
follower_conf.node.data_url = format!("http://{localhost}:{rpc_port}");
12479+
follower_conf.node.p2p_address = format!("{localhost}:{p2p_port}");
12480+
follower_conf.node.pox_sync_sample_secs = 30;
1248112481

1248212482
let run_loop_thread = thread::spawn(move || miner_run_loop.start(None, 0));
1248312483
wait_for_runloop(&miner_blocks_processed);
@@ -12657,15 +12657,8 @@ fn mock_miner_replay() {
1265712657
follower_conf.node.seed = vec![0x01; 32];
1265812658
follower_conf.node.local_peer_seed = vec![0x02; 32];
1265912659

12660-
let mut rng = rand::thread_rng();
12661-
12662-
let (rpc_port, p2p_port) = loop {
12663-
let a = rng.gen_range(1024..u16::MAX); // use a non-privileged port between 1024 and 65534
12664-
let b = rng.gen_range(1024..u16::MAX); // use a non-privileged port between 1024 and 65534
12665-
if a != b {
12666-
break (a, b);
12667-
}
12668-
};
12660+
let rpc_port = gen_random_port();
12661+
let p2p_port = gen_random_port();
1266912662

1267012663
let localhost = "127.0.0.1";
1267112664
follower_conf.node.rpc_bind = format!("{localhost}:{rpc_port}");
@@ -12800,7 +12793,9 @@ fn listunspent_max_utxos() {
1280012793
}
1280112794

1280212795
let (mut conf, _miner_account) = neon_integration_test_conf();
12803-
let prom_bind = format!("{}:{}", "127.0.0.1", 6000);
12796+
let prom_port = gen_random_port();
12797+
let localhost = "127.0.0.1";
12798+
let prom_bind = format!("{localhost}:{prom_port}");
1280412799
conf.node.prometheus_bind = Some(prom_bind.clone());
1280512800

1280612801
conf.burnchain.max_rbf = 1000000;
@@ -12846,7 +12841,9 @@ fn start_stop_bitcoind() {
1284612841
}
1284712842

1284812843
let (mut conf, _miner_account) = neon_integration_test_conf();
12849-
let prom_bind = format!("{}:{}", "127.0.0.1", 6000);
12844+
let prom_port = gen_random_port();
12845+
let localhost = "127.0.0.1";
12846+
let prom_bind = format!("{localhost}:{prom_port}");
1285012847
conf.node.prometheus_bind = Some(prom_bind.clone());
1285112848

1285212849
conf.burnchain.max_rbf = 1000000;

0 commit comments

Comments
 (0)