Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8aa7bed
PersistentConfiguration now handles CryptDEs
dnwiebe Apr 29, 2025
02e059c
Temporary commit
dnwiebe May 21, 2025
b49606b
All tests apparently passing
dnwiebe May 29, 2025
c3d18a3
Starting to deal with the consequences of removing CryptDE as a static
dnwiebe Jun 27, 2025
c6887b9
About two-thirds done.
dnwiebe Jun 27, 2025
0b5a864
All unit tests passing
dnwiebe Jun 30, 2025
c66e762
New integration test is passing
dnwiebe Jul 1, 2025
a42c445
Merged in master
dnwiebe Jul 1, 2025
7295793
Unit, integration, and multinode tests passing
dnwiebe Jul 2, 2025
e3d2126
Review issues
dnwiebe Jul 3, 2025
b89a378
Removed two fields from BootstrapperConfig
dnwiebe Jul 3, 2025
2468554
Formatting
dnwiebe Jul 3, 2025
4437d36
Review issues
dnwiebe Jul 4, 2025
1bba5fe
Removed unused second parameter to CrashTestDummy constructor
dnwiebe Jul 4, 2025
828a354
Formatting
dnwiebe Jul 4, 2025
55334db
Changing the way database passwords are established
dnwiebe Jul 10, 2025
04c0365
Formatting
dnwiebe Jul 10, 2025
2f16112
Trying to find issue with --fake-public-key and chain
dnwiebe Jul 16, 2025
e6707e3
Multinode tests and unit tests are working.
dnwiebe Jul 16, 2025
4dfb97f
Formatting and removing debug logs
dnwiebe Jul 16, 2025
4671266
Removed unused import
dnwiebe Jul 16, 2025
09f953e
Clippy appeasement
dnwiebe Jul 17, 2025
c76a5bb
Review issues
dnwiebe Jul 18, 2025
ccd602d
Formatting
dnwiebe Jul 18, 2025
e52c338
Switched test from example.com to testingmcafeesites.com
dnwiebe Jul 19, 2025
83e37fa
Made running single integration tests easier; added TLS retries to in…
dnwiebe Jul 21, 2025
8d060fe
Formatting
dnwiebe Jul 21, 2025
7cf6856
Race in setup_reporter removed
dnwiebe Jul 29, 2025
843570b
Increased a timeout
dnwiebe Jul 30, 2025
c5c94db
Formatting
dnwiebe Jul 30, 2025
2fc19f1
example.com -> www.example.com
dnwiebe Jul 30, 2025
45f2e17
Review issues
dnwiebe Jul 31, 2025
49ac096
SetupReporter tests are modified and passing
dnwiebe Aug 1, 2025
b10a1d1
Parsing command-line parameter
dnwiebe Aug 2, 2025
fc0092a
Implemented --new-public-key
dnwiebe Aug 3, 2025
f8e49d9
--new-public-key default is now '' / Blank
dnwiebe Aug 4, 2025
f2fded4
Review issues
dnwiebe Aug 5, 2025
2de18ad
Merged in master
dnwiebe Sep 1, 2025
dabeddb
Now we know what to do, but there's a missing test
dnwiebe Sep 17, 2025
0692008
Now the GH-623 problem should be fixed
dnwiebe Sep 17, 2025
52a125b
Merge branch 'master' into GH-623
dnwiebe Oct 29, 2025
ca20258
Merge branch 'master' into GH-623
kauri-hero Feb 1, 2026
0fd631f
Merge branch 'GH-623' of github.com:MASQ-Project/Node into GH-623
dnwiebe Feb 3, 2026
f5d04ee
.gitignore for Copilot
dnwiebe Feb 3, 2026
31c0f59
Added newly-required --blockchain-service-url parameter to a test
dnwiebe Feb 3, 2026
7985416
Did some (not all) switching from www.example.com to www.testingmcafe…
dnwiebe Feb 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Temporary Items
**/.idea/markdown-navigator/**
**/.idea/aws.xml
**/.idea/scopes/*.xml
**/.idea/copilot*

# Sensitive or high-churn files:
**/.idea/**/dataSources/
Expand Down
33 changes: 31 additions & 2 deletions masq_lib/src/shared_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::constants::{
POLYGON_MAINNET_FULL_IDENTIFIER,
};
use crate::crash_point::CrashPoint;
use clap::{App, Arg};
use clap::{arg_enum, App, Arg};
use lazy_static::lazy_static;

pub const BLOCKCHAIN_SERVICE_HELP: &str =
Expand Down Expand Up @@ -81,6 +81,17 @@ pub const NEIGHBORS_HELP: &str = "One or more Node descriptors for running Nodes
if you don't specify a neighbor, your Node will start without being connected to any MASQ \
Network, although other Nodes will be able to connect to yours if they know your Node's descriptor. \
--neighbors is meaningless in --neighborhood-mode zero-hop.";
pub const NEW_PUBLIC_KEY_HELP: &str = "Whenever you start it, the Node will try to use the same public key \
it used last time. That's '--new-public-key off'. If you want it to select a new public key when it \
starts, then specify '--new-public-key on', and you'll get a different one this time...which it will \
reuse next time unless you specify '--new-public-key on' again.\n\n\
You should be careful about restarting your Node with the same public key too quickly. If your new \
Node tries to join the Network before the Network has forgotten your old Node, every Node you try \
to connect to will ignore you.\n\n\
There are some conditions under which the Node cannot use the same public key it used last time: \
for example, if there was no last time, or if you don't specify a `--db-password`. Normally, in \
these situations, the Node will select a new public key and store it for future use; but if you \
explicitly demand the old public key with `--new-public-key off`, the Node will refuse to start.";

// generated valid encoded keys for future needs
// UJNoZW5p/PDVqEjpr3b+8jZ/93yPG8i5dOAgE1bhK+A
Expand Down Expand Up @@ -226,6 +237,14 @@ lazy_static! {
DEFAULT_GAS_PRICE);
}

arg_enum! {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum OnOff {
On,
Off,
}
}

// These Args are needed in more than one clap schema. To avoid code duplication, they're defined here and referred
// to from multiple places.
pub fn chain_arg<'a>() -> Arg<'a, 'a> {
Expand Down Expand Up @@ -467,13 +486,23 @@ pub fn shared_app(head: App<'static, 'static>) -> App<'static, 'static> {
.min_values(0)
.help(NEIGHBORS_HELP),
)
.arg(
Arg::with_name("new-public-key")
.long("new-public-key")
.value_name("NEW-PUBLIC-KEY")
.takes_value(true)
.possible_values(&OnOff::variants())
.case_insensitive(true)
.help(NEW_PUBLIC_KEY_HELP),
)
.arg(real_user_arg())
.arg(
Arg::with_name("scans")
.long("scans")
.value_name("SCANS")
.takes_value(true)
.possible_values(&["on", "off"])
.possible_values(&OnOff::variants())
.case_insensitive(true)
.help(SCANS_HELP),
)
.arg(common_parameter_with_separate_u64_values(
Expand Down
57 changes: 38 additions & 19 deletions multinode_integration_tests/tests/bookkeeping_test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
use itertools::Itertools;
use multinode_integration_tests_lib::masq_node::{MASQNode, NodeReference};
use multinode_integration_tests_lib::masq_node_cluster::MASQNodeCluster;
use multinode_integration_tests_lib::masq_real_node::{
Expand Down Expand Up @@ -30,54 +31,72 @@ fn provided_and_consumed_services_are_recorded_in_databases() {

let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);
client.set_timeout(Duration::from_secs(10));
let request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n".as_bytes();
let request = "GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n".as_bytes();

client.send_chunk(request);
let response = String::from_utf8(client.wait_for_chunk()).unwrap();
assert!(
response.contains("<h1>Example Domain</h1>"),
"Not from www.example.com:\n{}",
response.contains("<title>URL for testing.</title>"),
"Not from www.testingmcafeesites.com:\n{}",
response
);

// Waiting until everybody has finished generating payables and receivables
thread::sleep(Duration::from_secs(10));

// get all payables from originating node
let payables = non_pending_payables(&originating_node);

// Waiting until the serving nodes have finished accruing their receivables
thread::sleep(Duration::from_secs(10));

// get all receivables from all other nodes
let receivable_balances = non_originating_nodes
let receivable_nodes = non_originating_nodes
.iter()
.flat_map(|node| {
receivables(node)
.into_iter()
.map(move |receivable_account| {
(node.earning_wallet(), receivable_account.balance_wei)
(
node.earning_wallet(),
(node.name().to_string(), receivable_account.balance_wei),
)
})
})
.collect::<HashMap<Wallet, i128>>();
.collect::<HashMap<Wallet, (String, i128)>>();

// check that each payable has a receivable
assert_eq!(
payables.len(),
receivable_balances.len(),
receivable_nodes.len(),
"Lengths of payables and receivables should match.\nPayables: {:?}\nReceivables: {:?}",
payables,
receivable_balances
receivable_nodes
);
assert!(
receivable_balances.len() >= 3, // minimum service list: route, route, exit.
receivable_nodes.len() >= 3, // minimum service list: route, route, exit.
"not enough receivables found {:?}",
receivable_balances
receivable_nodes
);

payables.iter().for_each(|payable| {
assert_eq!(
payable.balance_wei,
*receivable_balances.get(&payable.wallet).unwrap() as u128,
);
});
let messages = payables
.iter()
.flat_map(|payable| {
let payable_balance = payable.balance_wei;
let (non_originating_node_name, receivable_balance) =
receivable_nodes.get(&payable.wallet).unwrap().clone();
if payable_balance != receivable_balance as u128 {
Some(format!(
"Payable for {} ({}) does not match receivable for {} ({})",
originating_node.name(),
payable_balance,
non_originating_node_name,
receivable_balance
))
} else {
None
}
})
.collect_vec();

assert!(messages.is_empty(), "{:#?}", messages);
}

fn non_pending_payables(node: &MASQRealNode) -> Vec<PayableAccount> {
Expand Down
79 changes: 54 additions & 25 deletions multinode_integration_tests/tests/data_routing_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ fn http_end_to_end_routing_test() {
thread::sleep(Duration::from_millis(500));

let mut client = last_node.make_client(8080, 5000);
client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
client.send_chunk(b"GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n");
let response = client.wait_for_chunk();

assert_eq!(
index_of(&response, &b"<h1>Example Domain</h1>"[..]).is_some(),
index_of(&response, &b"<title>URL for testing.</title>"[..]).is_some(),
true,
"Actual response:\n{}",
String::from_utf8(response).unwrap()
Expand Down Expand Up @@ -104,11 +104,11 @@ fn http_end_to_end_routing_test_with_consume_and_originate_only_nodes() {
thread::sleep(Duration::from_millis(1000));

let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);
client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
client.send_chunk(b"GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n");
let response = client.wait_for_chunk();

assert_eq!(
index_of(&response, &b"<h1>Example Domain</h1>"[..]).is_some(),
index_of(&response, &b"<title>URL for testing.</title>"[..]).is_some(),
true,
"Actual response:\n{}",
String::from_utf8(response).unwrap()
Expand Down Expand Up @@ -235,11 +235,11 @@ fn http_routing_failure_produces_internal_error_response() {

let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);

client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
client.send_chunk(b"GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n");
let response = client.wait_for_chunk();

let expected_response =
ServerImpersonatorHttp {}.route_query_failure_response("www.example.com");
ServerImpersonatorHttp {}.route_query_failure_response("www.testingmcafeesites.com");

assert_eq!(
&expected_response,
Expand Down Expand Up @@ -315,27 +315,56 @@ fn multiple_stream_zero_hop_test() {
let mut one_client = zero_hop_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);
let mut another_client = zero_hop_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS);

one_client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
another_client.send_chunk(b"GET / HTTP/1.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Language: cs-CZ,cs;q=0.9,en;q=0.8,sk;q=0.7\r\nCache-Control: max-age=0\r\nConnection: keep-alive\r\nHost: www.testingmcafeesites.com\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\r\n\r\n");
one_client.send_chunk(b"GET /testcat_ed.html HTTP/1.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Language: cs-CZ,cs;q=0.9,en;q=0.8,sk;q=0.7\r\nCache-Control: max-age=0\r\nConnection: keep-alive\r\nHost: www.testingmcafeesites.com\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\r\n\r\n");
another_client.send_chunk(b"GET /testcat_cm.html HTTP/1.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Language: cs-CZ,cs;q=0.9,en;q=0.8,sk;q=0.7\r\nCache-Control: max-age=0\r\nConnection: keep-alive\r\nHost: www.testingmcafeesites.com\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\r\n\r\n");

let one_response = one_client.wait_for_chunk();
let another_response = another_client.wait_for_chunk();

assert_eq!(
index_of(&one_response, &b"<h1>Example Domain</h1>"[..]).is_some(),
true,
"Actual response:\n{}",
String::from_utf8(one_response).unwrap()
);
assert_eq!(
index_of(
&another_response,
&b"This is an index url which gives an overview of the different test urls available."
[..],
)
.is_some(),
true,
"Actual response:\n{}",
String::from_utf8(another_response).unwrap()
);
{
assert_eq!(
index_of(
&one_response,
&b"Education/Reference website with a low risk reputation score"[..]
)
.is_some(),
true,
"Actual response:\n{}",
String::from_utf8(one_response).unwrap()
);
assert_eq!(
index_of(
&one_response,
&b"This page simply displays this text without any specific content on it, it is just for testing purpose."
[..],
)
.is_some(),
true,
"Actual response:\n{}",
String::from_utf8(one_response).unwrap()
);
}
{
assert_eq!(
index_of(
&another_response,
&b"Public Information website with a low risk reputation score"[..]
)
.is_some(),
true,
"Actual response:\n{}",
String::from_utf8(another_response).unwrap()
);
assert_eq!(
index_of(
&another_response,
&b"This page simply displays this text without any specific content on it, it is just for testing purpose."
[..],
)
.is_some(),
true,
"Actual response:\n{}",
String::from_utf8(another_response).unwrap()
);
}
}
12 changes: 6 additions & 6 deletions multinode_integration_tests/tests/min_hops_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ fn assert_http_end_to_end_routing(min_hops: Hops) {

let last_node = nodes.last().unwrap();
let mut client = last_node.make_client(8080, 5000);
client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
client.send_chunk(b"GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n");
let response = client.wait_for_chunk();

assert_eq!(
index_of(&response, &b"<h1>Example Domain</h1>"[..]).is_some(),
index_of(&response, &b"<title>URL for testing.</title>"[..]).is_some(),
true,
"Actual response:\n{}",
String::from_utf8(response).unwrap()
Expand Down Expand Up @@ -84,14 +84,14 @@ fn min_hops_can_be_changed_during_runtime() {
thread::sleep(Duration::from_millis(1000));

let mut client = first_node.make_client(8080, 5000);
client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
client.send_chunk(b"GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n");
let response = client.wait_for_chunk();

// Client shutdown is necessary to re-initialize stream keys for old requests
client.shutdown();

assert_eq!(
index_of(&response, &b"<h1>Example Domain</h1>"[..]).is_some(),
index_of(&response, &b"<title>URL for testing.</title>"[..]).is_some(),
true,
"Actual response:\n{}",
String::from_utf8(response).unwrap()
Expand All @@ -108,12 +108,12 @@ fn min_hops_can_be_changed_during_runtime() {
assert!(response.payload.is_ok());

let mut client = first_node.make_client(8080, 5000);
client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n");
client.send_chunk(b"GET /index.html HTTP/1.1\r\nHost: www.testingmcafeesites.com\r\n\r\n");
let response = client.wait_for_chunk();
assert_eq!(
index_of(
&response,
&b"<h3>Subtitle: Can't find a route to www.example.com</h3>"[..]
&b"<h3>Subtitle: Can't find a route to www.testingmcafeesites.com</h3>"[..]
)
.is_some(),
true,
Expand Down
4 changes: 4 additions & 0 deletions node/src/actor_system_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,7 @@ mod tests {
data_directory: PathBuf::new(),
node_descriptor: NodeDescriptor::default(),
mapping_protocol_opt: None,
new_public_key_opt: None,
real_user: RealUser::null(),
neighborhood_config: NeighborhoodConfig {
mode: NeighborhoodMode::Standard(
Expand Down Expand Up @@ -1211,6 +1212,7 @@ mod tests {
cryptde_pair: CRYPTDE_PAIR.clone(),
mapping_protocol_opt: Some(Igdp),
real_user: RealUser::null(),
new_public_key_opt: None,
neighborhood_config: NeighborhoodConfig {
mode: NeighborhoodMode::Standard(
NodeAddr::new(&IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), &[1234, 2345]),
Expand Down Expand Up @@ -1507,6 +1509,7 @@ mod tests {
cryptde_pair: CRYPTDE_PAIR.clone(),
mapping_protocol_opt: None,
real_user: RealUser::null(),
new_public_key_opt: None,
neighborhood_config: NeighborhoodConfig {
mode: NeighborhoodMode::ConsumeOnly(vec![]),
min_hops: MIN_HOPS_FOR_TEST,
Expand Down Expand Up @@ -1690,6 +1693,7 @@ mod tests {
cryptde_pair: CRYPTDE_PAIR.clone(),
mapping_protocol_opt: None,
real_user: RealUser::null(),
new_public_key_opt: None,
neighborhood_config: NeighborhoodConfig {
mode: NeighborhoodMode::Standard(
NodeAddr::new(&IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), &[]),
Expand Down
2 changes: 2 additions & 0 deletions node/src/bootstrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ pub struct BootstrapperConfig {
pub node_descriptor: NodeDescriptor,
pub cryptde_pair: CryptDEPair,
pub mapping_protocol_opt: Option<AutomapProtocol>,
pub new_public_key_opt: Option<bool>,
pub real_user: RealUser,
pub payment_thresholds_opt: Option<PaymentThresholds>,

Expand Down Expand Up @@ -406,6 +407,7 @@ impl BootstrapperConfig {
Box::new(CryptDEReal::disabled()),
),
mapping_protocol_opt: None,
new_public_key_opt: None,
real_user: RealUser::new(None, None, None),
payment_thresholds_opt: Default::default(),

Expand Down
Loading
Loading