diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..54960b032
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,106 @@
+# Basic `dependabot.yml` file with
+# minimum configuration for two package managers
+
+version: 2
+updates:
+ # Enable version updates for node
+ - package-ecosystem: "cargo"
+ directory: "/node"
+ # Check the cargo registry for updates every day (weekdays)
+ schedule:
+ interval: "daily"
+ time: '14:00'
+ timezone: 'Etc/UTC'
+ allow:
+ - dependency-name: "*"
+ dependency-type: "direct"
+ ignore:
+ - dependency-name: "automap"
+ - dependency-name: "masq_lib"
+ - dependency-name: "actix"
+ - dependency-name: "tokio"
+ - dependency-name: "clap"
+ - dependency-name: "sodiumoxide"
+ - dependency-name: "web3"
+ - dependency-name: "websocket"
+ groups:
+ patch:
+ update-types:
+ - "patch"
+ minor:
+ update-types:
+ - "minor"
+ target-branch: 'master'
+ open-pull-requests-limit: 2
+
+ # Enable version updates for masq
+ - package-ecosystem: "cargo"
+ directory: "/masq"
+ # Check the cargo registry for updates every day (weekdays)
+ schedule:
+ interval: "daily"
+ time: '14:00'
+ timezone: 'Etc/UTC'
+ allow:
+ - dependency-name: "*"
+ dependency-type: "direct"
+ ignore:
+ - dependency-name: "masq_lib"
+ - dependency-name: "clap"
+ - dependency-name: "websocket"
+ groups:
+ patch:
+ update-types:
+ - "patch"
+ minor:
+ update-types:
+ - "minor"
+ target-branch: 'master'
+ open-pull-requests-limit: 2
+
+ # Enable version updates for masq_lib
+ - package-ecosystem: "cargo"
+ directory: "/masq_lib"
+ # Check the cargo registry for updates every day (weekdays)
+ schedule:
+ interval: "daily"
+ time: '14:00'
+ timezone: 'Etc/UTC'
+ allow:
+ - dependency-name: "*"
+ dependency-type: "direct"
+ ignore:
+ - dependency-name: "clap"
+ - dependency-name: "websocket"
+ groups:
+ patch:
+ update-types:
+ - "patch"
+ minor:
+ update-types:
+ - "minor"
+ target-branch: 'master'
+ open-pull-requests-limit: 2
+
+ # Enable version updates for automap
+ - package-ecosystem: "cargo"
+ directory: "/automap"
+ # Check the cargo registry for updates every day (weekdays)
+ schedule:
+ interval: "daily"
+ time: '14:00'
+ timezone: 'Etc/UTC'
+ allow:
+ - dependency-name: "*"
+ dependency-type: "direct"
+ ignore:
+ - dependency-name: "masq_lib"
+ groups:
+ patch:
+ update-types:
+ - "patch"
+ minor:
+ update-types:
+ - "minor"
+ target-branch: 'master'
+ open-pull-requests-limit: 2
diff --git a/.github/workflows/ci-matrix.yml b/.github/workflows/ci-matrix.yml
index 3b7c44c7a..193cc2107 100644
--- a/.github/workflows/ci-matrix.yml
+++ b/.github/workflows/ci-matrix.yml
@@ -4,7 +4,7 @@ on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- - master
+ - GH-784
jobs:
build:
@@ -14,7 +14,7 @@ jobs:
matrix:
target:
- { name: linux, os: ubuntu-22.04 }
- - { name: macos, os: macos-14 }
+ - { name: macos, os: macos-13 }
- { name: windows, os: windows-2022 }
name: Build node on ${{ matrix.target.os }}
@@ -23,6 +23,12 @@ jobs:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
+
+ - name: Print source branch name
+ run: |
+ echo "Source branch: ${{ github.head_ref }}"
+ shell: bash
+
- name: Stable with rustfmt and clippy
uses: actions-rs/toolchain@v1
with:
@@ -40,14 +46,16 @@ jobs:
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo
+
- name: Build ${{ matrix.target.os }}
run: |
./ci/all.sh
./ci/multinode_integration_test.sh
./ci/collect_results.sh
shell: bash
+
- name: Publish ${{ matrix.target.os }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: Node-${{ matrix.target.name }}
path: results
@@ -67,7 +75,8 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}
- - uses: actions/download-artifact@v3
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
- name: Display structure of downloaded files
run: ls -R
@@ -82,7 +91,7 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: 'us-west-2'
- DEST_DIR: 'Node/${{ github.event.workflow_run.head_branch }}/Node-${{ matrix.os }}'
+ DEST_DIR: 'Node/${{ github.head_ref }}/Node-${{ matrix.os }}'
SOURCE_DIR: 'Node-${{ matrix.os }}/generated/bin/'
- if: startsWith(github.head_ref, 'v')
@@ -105,4 +114,4 @@ jobs:
PATHS: "/Node*"
AWS_REGION: "us-west-2"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
\ No newline at end of file
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
diff --git a/.idea/modules.xml b/.idea/modules.xml
index c32b128d9..861973a36 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -10,6 +10,7 @@
+
\ No newline at end of file
diff --git a/README.md b/README.md
index f739378e5..84fb5ac44 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,12 @@
# MASQ Node 
+
+

+[](https://github.com/MASQ-Project/Node/releases/latest)
+[](https://discord.gg/masq)
+
+
MASQ Node combines the benefits of VPN and Tor technology, to create superior next-generation privacy software, where
users are rewarded for supporting an uncensored, global Web. Users gain privacy and anonymity, while helping promote
@@ -33,8 +39,7 @@ stage - MASQ Network and it's developers are not responsible for any activity, o
## Source
The MASQ project was forked from Substratum's Node project in order to carry on development after Substratum ceased
operations in October of 2019. In 2021, Substratum's Node repositories were removed from GitHub, so the fork link
-with MASQ was broken, but all credit for the original idea, the original design, and the first two years of MASQ's
-development belongs to Substratum.
+with MASQ was broken, but all credit for the original idea and the original design belongs to Substratum (and properly attributed through GPLv3 license)
## Running the MASQ Node
@@ -43,7 +48,7 @@ A [Knowledge Base](https://docs.masq.ai/masq) and testing resources are being re
levels of technical ability.
There you can find further information, guides and configuration examples for running MASQ Node from:
-- MASQ app - v0.2 (formerly called "GEMINI")
+- [MASQ Browser](https://masqbrowser.com)
- CLI
- Docker image
@@ -66,7 +71,7 @@ To help navigate the codebase, here are the README.md links for all documented c
### Downloading Official Releases
-We haven't set up any official releases yet; but when we do, instructions will appear here.
+Releases will appear on our GitHub page - click on the badge above for the latest stable beta build, or go to our [Releases page](https://github.com/MASQ-Project/Node/releases/latest)
### Downloading the Latest Build
@@ -446,6 +451,4 @@ recommend using a 64-bit version to build.
We do plan to release binaries that will run on 32-bit Windows, but they will likely be built on 64-bit Windows.
-Copyright (c) 2019-2022, MASQ Network
-
-Copyright (c) 2017-2019, Substratum LLC and/or its affiliates. All rights reserved.
+Copyright (c) 2019-2024, MASQ Network
diff --git a/USER-INTERFACE-INTERFACE.md b/USER-INTERFACE-INTERFACE.md
index c53e420cc..c7059929a 100644
--- a/USER-INTERFACE-INTERFACE.md
+++ b/USER-INTERFACE-INTERFACE.md
@@ -512,7 +512,7 @@ There are following three connection stages:
1. NotConnected: No external neighbor is connected to us.
2. ConnectedToNeighbor: External node(s) are connected to us.
-3. ThreeHopsRouteFound: You can relay data over the network.
+3. RouteFound: You can relay data over the network.
The Node can only be on one of these connection stages during any moment of the Node's lifetime.
@@ -1095,6 +1095,18 @@ even for parameters whose values are natively of other types.
##### Description:
If the value of the respective parameter was successfully changed, this is a simple acknowledgment that the change is complete.
+The following commands can be configured using the `setConfiguration`:
+
+
+| Name | Parameter | Possible Values |
+|------------------|-----------------|------------------|
+| Gas Price | `--gas-price` | > 0 |
+| Start Block | `--start-block` | > 0 |
+| Min Hops | `--min-hops` | [1, 6] |
+
+
+Note: The descriptions for the above commands can be found [here](#permitted-names).
+
#### `setup`
##### Direction: Request
##### Correspondent: Daemon
@@ -1131,10 +1143,11 @@ be cleared.
* `db-password` - Password to unlock the sensitive values in the database.
* `dns-servers` - Comma-separated list of DNS servers to use.
* `earning-wallet` - Wallet into which earnings should be deposited.
-* `gas-price` - Transaction fee to offer on the blockchain.
+* `gas-price` - The fee per unit of computational effort in blockchain transactions, measured in gwei.
* `ip` - The public IP address of the Node.
* `log-level` - The lowest level of logs that should be recorded. `off`, `error`, `warn`, `info`, `debug`, `trace`
* `mapping-protocol` - The management protocol to try first with the router. `pcp`, `pmp`, `igdp`
+* `min-hops`: The minimum number of hops required for the package to reach the Exit Node.
* `neighborhood-mode` - `zero-hop`, `originate-only`, `consume-only`, `standard`
* `neighbors` - Comma-separated list of Node descriptors for neighbors to contact on startup
* `real-user` - Non-Windows platforms only, only where required: ::
diff --git a/automap/Cargo.lock b/automap/Cargo.lock
index c970dc200..e1f3984db 100644
--- a/automap/Cargo.lock
+++ b/automap/Cargo.lock
@@ -137,7 +137,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "automap"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"crossbeam-channel 0.5.8",
"flexi_logger",
@@ -464,6 +464,27 @@ dependencies = [
"subtle 1.0.0",
]
+[[package]]
+name = "csv"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
+dependencies = [
+ "csv-core",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "cxx"
version = "1.0.94"
@@ -901,6 +922,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "ip_country"
+version = "0.1.0"
+dependencies = [
+ "csv",
+ "itertools 0.13.0",
+ "lazy_static",
+]
+
[[package]]
name = "ipconfig"
version = "0.1.9"
@@ -923,6 +953,15 @@ dependencies = [
"either",
]
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "1.0.6"
@@ -1051,7 +1090,7 @@ dependencies = [
[[package]]
name = "masq_lib"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"actix",
"clap",
@@ -1059,7 +1098,8 @@ dependencies = [
"crossbeam-channel 0.5.8",
"dirs",
"ethereum-types",
- "itertools",
+ "ip_country",
+ "itertools 0.10.5",
"lazy_static",
"log 0.4.17",
"nix",
@@ -1067,6 +1107,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
+ "test_utilities",
"time 0.3.20",
"tiny-hderive",
"toml",
@@ -1927,6 +1968,10 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "test_utilities"
+version = "0.1.0"
+
[[package]]
name = "textwrap"
version = "0.11.0"
diff --git a/automap/Cargo.toml b/automap/Cargo.toml
index c89c47ced..21c1acf91 100644
--- a/automap/Cargo.toml
+++ b/automap/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "automap"
-version = "0.8.0"
+version = "0.8.2"
authors = ["Dan Wiebe ", "MASQ"]
license = "GPL-3.0-only"
description = "Library full of code to make routers map ports through firewalls"
diff --git a/ci/all.sh b/ci/all.sh
index 2f381c45c..6591cd392 100755
--- a/ci/all.sh
+++ b/ci/all.sh
@@ -8,7 +8,7 @@ ci/format.sh
export RUST_BACKTRACE=1
# Remove these two lines to slow down the build
-which sccache || cargo install sccache || echo "Skipping sccache installation" # Should do significant work only once
+which sccache || cargo install --version 0.4.1 sccache || echo "Skipping sccache installation" # Should do significant work only once
#export CARGO_TARGET_DIR="$CI_DIR/../cargo-cache"
export SCCACHE_DIR="$HOME/.cargo/sccache"
#export RUSTC_WRAPPER="$HOME/.cargo/bin/sccache"
diff --git a/dns_utility/Cargo.lock b/dns_utility/Cargo.lock
index 52a3ec6b3..7c7d11ac5 100644
--- a/dns_utility/Cargo.lock
+++ b/dns_utility/Cargo.lock
@@ -399,6 +399,27 @@ dependencies = [
"subtle 1.0.0",
]
+[[package]]
+name = "csv"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
+dependencies = [
+ "csv-core",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "digest"
version = "0.8.1"
@@ -430,7 +451,7 @@ dependencies = [
[[package]]
name = "dns_utility"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"core-foundation",
"ipconfig 0.2.2",
@@ -716,6 +737,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "ip_country"
+version = "0.1.0"
+dependencies = [
+ "csv",
+ "itertools 0.13.0",
+ "lazy_static",
+]
+
[[package]]
name = "ipconfig"
version = "0.1.9"
@@ -750,6 +780,15 @@ dependencies = [
"either",
]
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "1.0.6"
@@ -854,7 +893,7 @@ dependencies = [
[[package]]
name = "masq_lib"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"actix",
"clap",
@@ -862,7 +901,8 @@ dependencies = [
"crossbeam-channel 0.5.8",
"dirs",
"ethereum-types",
- "itertools",
+ "ip_country",
+ "itertools 0.10.5",
"lazy_static",
"log 0.4.17",
"nix",
@@ -870,6 +910,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
+ "test_utilities",
"time 0.3.20",
"tiny-hderive",
"toml",
@@ -1653,6 +1694,10 @@ dependencies = [
"libc",
]
+[[package]]
+name = "test_utilities"
+version = "0.1.0"
+
[[package]]
name = "textwrap"
version = "0.11.0"
diff --git a/dns_utility/Cargo.toml b/dns_utility/Cargo.toml
index f8ce5620f..50f358db8 100644
--- a/dns_utility/Cargo.toml
+++ b/dns_utility/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "dns_utility"
-version = "0.8.0"
+version = "0.8.2"
license = "GPL-3.0-only"
authors = ["Dan Wiebe ", "MASQ"]
copyright = "Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved."
diff --git a/ip_country/Cargo.toml b/ip_country/Cargo.toml
index 7ba43fb60..0e57d7cac 100644
--- a/ip_country/Cargo.toml
+++ b/ip_country/Cargo.toml
@@ -13,8 +13,9 @@ workspace = "../node"
csv = "1.3.0"
itertools = "0.13.0"
lazy_static = "1.4.0"
-masq_lib = { path = "../masq_lib" }
+[dev-dependencies]
+test_utilities = { path = "../test_utilities"}
[[bin]]
name = "ip_country"
diff --git a/ip_country/src/country_finder.rs b/ip_country/src/country_finder.rs
index 270ecd76c..114c89421 100644
--- a/ip_country/src/country_finder.rs
+++ b/ip_country/src/country_finder.rs
@@ -54,9 +54,7 @@ impl CountryCodeFinder {
#[cfg(test)]
mod tests {
use super::*;
- use crate::country_block_serde::{
- CountryBlockDeserializer, Ipv4CountryBlockDeserializer, Ipv6CountryBlockDeserializer,
- };
+ use crate::country_block_serde::{Ipv4CountryBlockDeserializer, Ipv6CountryBlockDeserializer};
use crate::dbip_country;
use std::str::FromStr;
use std::time::SystemTime;
diff --git a/ip_country/src/ip_country.rs b/ip_country/src/ip_country.rs
index abf461aba..f4a7cbe13 100644
--- a/ip_country/src/ip_country.rs
+++ b/ip_country/src/ip_country.rs
@@ -133,8 +133,8 @@ fn write_value(
#[cfg(test)]
mod tests {
use super::*;
- use masq_lib::test_utils::fake_stream_holder::{ByteArrayReader, ByteArrayWriter};
use std::io::{Error, ErrorKind};
+ use test_utilities::byte_array_reader_writer::{ByteArrayReader, ByteArrayWriter};
static PROPER_TEST_DATA: &str = "0.0.0.0,0.255.255.255,ZZ
1.0.0.0,1.0.0.255,AU
diff --git a/masq/Cargo.toml b/masq/Cargo.toml
index 87a20ad67..0a6484895 100644
--- a/masq/Cargo.toml
+++ b/masq/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "masq"
-version = "0.8.0"
+version = "0.8.2"
authors = ["Dan Wiebe ", "MASQ"]
license = "GPL-3.0-only"
description = "Reference implementation of user interface for MASQ Node"
@@ -28,6 +28,7 @@ nix = "0.23.0"
[dev-dependencies]
atty = "0.2.14"
+test_utilities = { path = "../test_utilities" }
[lib]
name = "masq_cli_lib"
diff --git a/masq/src/command_context.rs b/masq/src/command_context.rs
index 41308e5bb..e648da218 100644
--- a/masq/src/command_context.rs
+++ b/masq/src/command_context.rs
@@ -156,12 +156,12 @@ mod tests {
use crate::test_utils::mocks::TRANSACT_TIMEOUT_MILLIS_FOR_TESTS;
use masq_lib::messages::{FromMessageBody, UiCrashRequest, UiSetupRequest};
use masq_lib::messages::{ToMessageBody, UiShutdownRequest, UiShutdownResponse};
- use masq_lib::test_utils::fake_stream_holder::{ByteArrayReader, ByteArrayWriter};
use masq_lib::test_utils::mock_websockets_server::MockWebSocketsServer;
use masq_lib::ui_gateway::MessageBody;
use masq_lib::ui_gateway::MessagePath::Conversation;
use masq_lib::ui_traffic_converter::{TrafficConversionError, UnmarshalError};
use masq_lib::utils::{find_free_port, running_test};
+ use test_utilities::byte_array_reader_writer::{ByteArrayReader, ByteArrayWriter};
#[test]
fn constant_has_correct_values() {
diff --git a/masq/src/command_factory.rs b/masq/src/command_factory.rs
index 21222c454..6ec658903 100644
--- a/masq/src/command_factory.rs
+++ b/masq/src/command_factory.rs
@@ -8,6 +8,7 @@ use crate::commands::configuration_command::ConfigurationCommand;
use crate::commands::connection_status_command::ConnectionStatusCommand;
use crate::commands::crash_command::CrashCommand;
use crate::commands::descriptor_command::DescriptorCommand;
+use crate::commands::exit_location_command::SetExitLocationCommand;
use crate::commands::financials_command::FinancialsCommand;
use crate::commands::generate_wallets_command::GenerateWalletsCommand;
use crate::commands::recover_wallets_command::RecoverWalletsCommand;
@@ -52,6 +53,10 @@ impl CommandFactory for CommandFactoryReal {
Err(msg) => return Err(CommandSyntax(msg)),
},
"descriptor" => Box::new(DescriptorCommand::new()),
+ "exit-location" => match SetExitLocationCommand::new(pieces) {
+ Ok(command) => Box::new(command),
+ Err(msg) => return Err(CommandSyntax(msg)),
+ },
"financials" => match FinancialsCommand::new(pieces) {
Ok(command) => Box::new(command),
Err(msg) => return Err(CommandSyntax(msg)),
@@ -103,6 +108,7 @@ impl CommandFactoryReal {
mod tests {
use super::*;
use crate::command_factory::CommandFactoryError::UnrecognizedSubcommand;
+ use masq_lib::messages::CountryCodes;
#[test]
fn complains_about_unrecognized_subcommand() {
@@ -258,6 +264,34 @@ mod tests {
);
}
+ #[test]
+ fn factory_produces_exit_location() {
+ let subject = CommandFactoryReal::new();
+
+ let command = subject
+ .make(&[
+ "exit-location".to_string(),
+ "--country-codes".to_string(),
+ "CZ".to_string(),
+ ])
+ .unwrap();
+
+ assert_eq!(
+ command
+ .as_any()
+ .downcast_ref::()
+ .unwrap(),
+ &SetExitLocationCommand {
+ exit_locations: vec![CountryCodes {
+ country_codes: vec!["CZ".to_string()],
+ priority: 1
+ }],
+ fallback_routing: false,
+ show_countries: false,
+ }
+ );
+ }
+
#[test]
fn complains_about_set_configuration_command_with_no_parameters() {
let subject = CommandFactoryReal::new();
diff --git a/masq/src/commands/configuration_command.rs b/masq/src/commands/configuration_command.rs
index 8701f1617..62d2b4650 100644
--- a/masq/src/commands/configuration_command.rs
+++ b/masq/src/commands/configuration_command.rs
@@ -131,7 +131,10 @@ impl ConfigurationCommand {
dump_parameter_line(
stream,
"Start block:",
- &configuration.start_block.to_string(),
+ &configuration
+ .start_block_opt
+ .map(|m| m.separate_with_commas())
+ .unwrap_or_else(|| "[Latest]".to_string()),
);
Self::dump_value_list(stream, "Past neighbors:", &configuration.past_neighbors);
let payment_thresholds = Self::preprocess_combined_parameters({
@@ -333,7 +336,7 @@ mod tests {
exit_byte_rate: 129000000,
exit_service_rate: 160000000,
},
- start_block: 3456,
+ start_block_opt: None,
scan_intervals: UiScanIntervals {
pending_payable_sec: 150500,
payable_sec: 155000,
@@ -378,7 +381,7 @@ mod tests {
|Max block count: [Unlimited]\n\
|Neighborhood mode: standard\n\
|Port mapping protocol: PCP\n\
-|Start block: 3456\n\
+|Start block: [Latest]\n\
|Past neighbors: neighbor 1\n\
| neighbor 2\n\
|Payment thresholds: \n\
@@ -410,7 +413,7 @@ mod tests {
blockchain_service_url_opt: Some("https://infura.io/ID".to_string()),
current_schema_version: "schema version".to_string(),
clandestine_port: 1234,
- chain_name: "mumbai".to_string(),
+ chain_name: "amoy".to_string(),
gas_price: 2345,
max_block_count_opt: Some(100_000),
neighborhood_mode: "zero-hop".to_string(),
@@ -433,7 +436,7 @@ mod tests {
exit_byte_rate: 20,
exit_service_rate: 30,
},
- start_block: 3456,
+ start_block_opt: Some(1234567890u64),
scan_intervals: UiScanIntervals {
pending_payable_sec: 1000,
payable_sec: 1000,
@@ -467,7 +470,7 @@ mod tests {
"\
|NAME VALUE\n\
|Blockchain service URL: https://infura.io/ID\n\
-|Chain: mumbai\n\
+|Chain: amoy\n\
|Clandestine port: 1234\n\
|Consuming wallet private key: [?]\n\
|Current schema version: schema version\n\
@@ -476,7 +479,7 @@ mod tests {
|Max block count: 100,000\n\
|Neighborhood mode: zero-hop\n\
|Port mapping protocol: PCP\n\
-|Start block: 3456\n\
+|Start block: 1,234,567,890\n\
|Past neighbors: [?]\n\
|Payment thresholds: \n\
| Debt threshold: 2,500 gwei\n\
diff --git a/masq/src/commands/exit_location_command.rs b/masq/src/commands/exit_location_command.rs
new file mode 100644
index 000000000..552bab768
--- /dev/null
+++ b/masq/src/commands/exit_location_command.rs
@@ -0,0 +1,274 @@
+use crate::command_context::CommandContext;
+use crate::commands::commands_common::{
+ transaction, Command, CommandError, STANDARD_COMMAND_TIMEOUT_MILLIS,
+};
+use clap::{App, Arg, SubCommand};
+use masq_lib::as_any_ref_in_trait_impl;
+use masq_lib::messages::{CountryCodes, UiSetExitLocationRequest, UiSetExitLocationResponse};
+use masq_lib::shared_schema::common_validators;
+
+const EXIT_LOCATION_ABOUT: &str =
+ "If you activate exit-location preferences, all exit Nodes in countries you don't specify will be prohibited: \n\
+ that is, if there is no exit Node available in any of your preferred countries, you'll get an error. However, \
+ if you just want to make a suggestion, and you don't mind Nodes in other countries being used if nothing is available \
+ in your preferred countries, you can specify --fallback-routing, and you'll get no error unless there are no exit Nodes \
+ available anywhere.\n\n\
+ Here are some example commands:\n\
+ masq> exit-location // disable exit-location preferences\n\
+ masq> exit-location --fallback-routing // disable exit-location preferences\n\
+ masq> exit-location --country-codes \"CZ,PL|SK\" --fallback-routing \n\t// fallback-routing is ON, \"CZ\" and \"PL\" countries have same priority \"1\", \"SK\" has priority \"2\"\n\
+ masq> exit-location --country-codes \"CZ|SK\" \n\t// fallback-routing is OFF, \"CZ\" and \"SK\" countries have different priority\n";
+
+// TODO update following help when GH-469 is done with `To obtain codes, you can use the 'country-codes-list' (469 card command) command.`
+const COUNTRY_CODES_HELP: &str = "Establish a set of countries that your Node should try to use for exit Nodes. You should choose from the countries that host the \
+ Nodes in your Neighborhood. List the countries in order of preference, separated by vertical pipes (|). If your level of preference \
+ for a group of countries is the same, separate those countries by commas (,).\n\
+ You can specify country codes as follows:\n\n\
+ masq> exit-location --country-codes \"CZ,PL|SK\" \n\t// \"CZ\" and \"PL\" countries have same priority \"1\", \"SK\" has priority \"2\" \n\
+ masq> exit-location --country-codes \"CZ|SK\" \n\t// \"CZ\" and \"SK\" countries have different priority\n\n";
+
+const FALLBACK_ROUTING_HELP: &str = "If you just want to make a suggestion, and you don't mind Nodes in other countries being used if nothing is available \
+ in your preferred countries, you can specify --fallback-routing, and you'll get no error unless there are no exit Nodes \
+ available anywhere. \n Here are some examples: \n\n\
+ masq> exit-location --country-codes \"CZ\" --fallback-routing \n\t// Set exit-location for \"CZ\" country with fallback-routing on \n\
+ masq> exit-location --country-codes \"CZ\" \n\t// Set exit-location for \"CZ\" country with fallback-routing off \n\n";
+
+pub fn exit_location_subcommand() -> App<'static, 'static> {
+ SubCommand::with_name("exit-location").about(EXIT_LOCATION_ABOUT)
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct SetExitLocationCommand {
+ pub exit_locations: Vec,
+ pub fallback_routing: bool,
+ pub show_countries: bool,
+}
+
+impl SetExitLocationCommand {
+ pub fn new(pieces: &[String]) -> Result {
+ match set_exit_location_subcommand().get_matches_from_safe(pieces) {
+ Ok(matches) => {
+ let exit_locations = match matches.is_present("country-codes") {
+ true => matches
+ .values_of("country-codes")
+ .expect("Expected Country Codes")
+ .into_iter()
+ .enumerate()
+ .map(|(index, code)| CountryCodes::from((code.to_string(), index)))
+ .collect(),
+ false => vec![],
+ };
+ let fallback_routing = !matches!(
+ (
+ matches.is_present("fallback-routing"),
+ matches.is_present("country-codes")
+ ),
+ (false, true)
+ );
+ let show_countries = matches.is_present("show-countries");
+ Ok(SetExitLocationCommand {
+ exit_locations,
+ fallback_routing,
+ show_countries,
+ })
+ }
+
+ Err(e) => Err(format!("SetExitLocationCommand {}", e)),
+ }
+ }
+}
+
+impl Command for SetExitLocationCommand {
+ fn execute(&self, context: &mut dyn CommandContext) -> Result<(), CommandError> {
+ let input = UiSetExitLocationRequest {
+ exit_locations: self.exit_locations.clone(),
+ fallback_routing: self.fallback_routing,
+ show_countries: self.show_countries,
+ };
+
+ let _: UiSetExitLocationResponse =
+ transaction(input, context, STANDARD_COMMAND_TIMEOUT_MILLIS)?;
+ Ok(())
+ }
+
+ as_any_ref_in_trait_impl!();
+}
+
+pub fn set_exit_location_subcommand() -> App<'static, 'static> {
+ SubCommand::with_name("exit-location")
+ .about(EXIT_LOCATION_ABOUT)
+ .arg(
+ Arg::with_name("country-codes")
+ .long("country-codes")
+ .value_name("COUNTRY-CODES")
+ .value_delimiter("|")
+ .validator(common_validators::validate_exit_locations)
+ .help(COUNTRY_CODES_HELP)
+ .required(false),
+ )
+ .arg(
+ Arg::with_name("fallback-routing")
+ .long("fallback-routing")
+ .value_name("FALLBACK-ROUTING")
+ .help(FALLBACK_ROUTING_HELP)
+ .takes_value(false)
+ .required(false),
+ )
+ .arg(
+ Arg::with_name("show-countries")
+ .long("show-countries")
+ .value_name("SHOW-COUNTRIES")
+ .takes_value(false)
+ .required(false),
+ )
+}
+
+#[cfg(test)]
+pub mod tests {
+ use crate::commands::commands_common::{Command, STANDARD_COMMAND_TIMEOUT_MILLIS};
+ use crate::commands::exit_location_command::SetExitLocationCommand;
+ use crate::test_utils::mocks::CommandContextMock;
+ use masq_lib::messages::{
+ CountryCodes, ToMessageBody, UiSetExitLocationRequest, UiSetExitLocationResponse,
+ };
+ use std::sync::{Arc, Mutex};
+
+ #[test]
+ fn can_deserialize_ui_set_exit_location() {
+ let transact_params_arc = Arc::new(Mutex::new(vec![]));
+ let mut context = CommandContextMock::new()
+ .transact_params(&transact_params_arc)
+ .transact_result(Ok(UiSetExitLocationResponse {}.tmb(0)));
+ let stderr_arc = context.stderr_arc();
+ let subject = SetExitLocationCommand::new(&[
+ "exit-location".to_string(),
+ "--country-codes".to_string(),
+ "CZ,SK|AT,DE|PL".to_string(),
+ "--fallback-routing".to_string(),
+ ])
+ .unwrap();
+
+ let result = subject.execute(&mut context);
+
+ assert_eq!(result, Ok(()));
+ let expected_request = UiSetExitLocationRequest {
+ fallback_routing: true,
+ exit_locations: vec![
+ CountryCodes {
+ country_codes: vec!["CZ".to_string(), "SK".to_string()],
+ priority: 1,
+ },
+ CountryCodes {
+ country_codes: vec!["AT".to_string(), "DE".to_string()],
+ priority: 2,
+ },
+ CountryCodes {
+ country_codes: vec!["PL".to_string()],
+ priority: 3,
+ },
+ ],
+ show_countries: false,
+ };
+ let transact_params = transact_params_arc.lock().unwrap();
+ let expected_message_body = expected_request.tmb(0);
+ assert_eq!(
+ transact_params.as_slice(),
+ &[(expected_message_body, STANDARD_COMMAND_TIMEOUT_MILLIS)]
+ );
+ let stderr = stderr_arc.lock().unwrap();
+ assert_eq!(&stderr.get_string(), "");
+ }
+
+ #[test]
+ fn absence_of_fallback_routing_produces_fallback_routing_false() {
+ let transact_params_arc = Arc::new(Mutex::new(vec![]));
+ let mut context = CommandContextMock::new()
+ .transact_params(&transact_params_arc)
+ .transact_result(Ok(UiSetExitLocationResponse {}.tmb(0)));
+ let stderr_arc = context.stderr_arc();
+ let subject = SetExitLocationCommand::new(&[
+ "exit-location".to_string(),
+ "--country-codes".to_string(),
+ "CZ".to_string(),
+ ])
+ .unwrap();
+
+ let result = subject.execute(&mut context);
+
+ assert_eq!(result, Ok(()));
+ let expected_request = UiSetExitLocationRequest {
+ fallback_routing: false,
+ exit_locations: vec![CountryCodes {
+ country_codes: vec!["CZ".to_string()],
+ priority: 1,
+ }],
+ show_countries: false,
+ };
+ let transact_params = transact_params_arc.lock().unwrap();
+ let expected_message_body = expected_request.tmb(0);
+ assert_eq!(
+ transact_params.as_slice(),
+ &[(expected_message_body, STANDARD_COMMAND_TIMEOUT_MILLIS)]
+ );
+ let stderr = stderr_arc.lock().unwrap();
+ assert_eq!(&stderr.get_string(), "");
+ }
+
+ #[test]
+ fn providing_no_arguments_cause_exit_location_reset_request() {
+ let transact_params_arc = Arc::new(Mutex::new(vec![]));
+ let mut context = CommandContextMock::new()
+ .transact_params(&transact_params_arc)
+ .transact_result(Ok(UiSetExitLocationResponse {}.tmb(0)));
+ let stderr_arc = context.stderr_arc();
+ let subject = SetExitLocationCommand::new(&["exit-location".to_string()]).unwrap();
+
+ let result = subject.execute(&mut context);
+
+ assert_eq!(result, Ok(()));
+ let expected_request = UiSetExitLocationRequest {
+ fallback_routing: true,
+ exit_locations: vec![],
+ show_countries: false,
+ };
+ let transact_params = transact_params_arc.lock().unwrap();
+ let expected_message_body = expected_request.tmb(0);
+ assert_eq!(
+ transact_params.as_slice(),
+ &[(expected_message_body, STANDARD_COMMAND_TIMEOUT_MILLIS)]
+ );
+ let stderr = stderr_arc.lock().unwrap();
+ assert_eq!(&stderr.get_string(), "");
+ }
+
+ #[test]
+ fn providing_show_countries_cause_request_for_list_of_countries() {
+ let transact_params_arc = Arc::new(Mutex::new(vec![]));
+ let mut context = CommandContextMock::new()
+ .transact_params(&transact_params_arc)
+ .transact_result(Ok(UiSetExitLocationResponse {}.tmb(0)));
+ let stderr_arc = context.stderr_arc();
+ let subject = SetExitLocationCommand::new(&[
+ "exit-location".to_string(),
+ "--show-countries".to_string(),
+ ])
+ .unwrap();
+
+ let result = subject.execute(&mut context);
+
+ assert_eq!(result, Ok(()));
+ let expected_request = UiSetExitLocationRequest {
+ fallback_routing: true,
+ exit_locations: vec![],
+ show_countries: true,
+ };
+ let transact_params = transact_params_arc.lock().unwrap();
+ let expected_message_body = expected_request.tmb(0);
+ assert_eq!(
+ transact_params.as_slice(),
+ &[(expected_message_body, STANDARD_COMMAND_TIMEOUT_MILLIS)]
+ );
+ let stderr = stderr_arc.lock().unwrap();
+ assert_eq!(&stderr.get_string(), "");
+ }
+}
diff --git a/masq/src/commands/mod.rs b/masq/src/commands/mod.rs
index 44026ebf8..143dff8e1 100644
--- a/masq/src/commands/mod.rs
+++ b/masq/src/commands/mod.rs
@@ -7,6 +7,7 @@ pub mod configuration_command;
pub mod connection_status_command;
pub mod crash_command;
pub mod descriptor_command;
+pub mod exit_location_command;
pub mod financials_command;
pub mod generate_wallets_command;
pub mod recover_wallets_command;
diff --git a/masq/src/commands/set_configuration_command.rs b/masq/src/commands/set_configuration_command.rs
index 99d979f07..385a48bc9 100644
--- a/masq/src/commands/set_configuration_command.rs
+++ b/masq/src/commands/set_configuration_command.rs
@@ -7,6 +7,7 @@ use masq_lib::shared_schema::gas_price_arg;
use masq_lib::shared_schema::min_hops_arg;
use masq_lib::short_writeln;
use masq_lib::utils::ExpectValue;
+use std::num::IntErrorKind;
#[derive(Debug, PartialEq, Eq)]
pub struct SetConfigurationCommand {
@@ -35,9 +36,17 @@ impl SetConfigurationCommand {
}
fn validate_start_block(start_block: String) -> Result<(), String> {
- match start_block.parse::() {
- Ok(_) => Ok(()),
- _ => Err(start_block),
+ if "latest".eq_ignore_ascii_case(&start_block) || "none".eq_ignore_ascii_case(&start_block) {
+ Ok(())
+ } else {
+ match start_block.parse::() {
+ Ok(_) => Ok(()),
+ Err(e) if e.kind() == &IntErrorKind::PosOverflow => Err(
+ format!("Unable to parse '{}' into a starting block number or provide 'none' or 'latest' for the latest block number: digits exceed {}.",
+ start_block, u64::MAX),
+ ),
+ Err(e) => Err(format!("Unable to parse '{}' into a starting block number or provide 'none' or 'latest' for the latest block number: {}.", start_block, e))
+ }
}
}
@@ -59,7 +68,7 @@ impl Command for SetConfigurationCommand {
const SET_CONFIGURATION_ABOUT: &str =
"Sets Node configuration parameters being enabled for this operation when the Node is running.";
const START_BLOCK_HELP: &str =
- "Ordinal number of the Ethereum block where scanning for transactions will start.";
+ "Ordinal number of the Ethereum block where scanning for transactions will start. Use 'latest' or 'none' for Latest block.";
pub fn set_configurationify<'a>(shared_schema_arg: Arg<'a, 'a>) -> Arg<'a, 'a> {
shared_schema_arg.takes_value(true).min_values(1)
@@ -84,6 +93,8 @@ pub fn set_configuration_subcommand() -> App<'static, 'static> {
.args(&["gas-price", "min-hops", "start-block"])
.required(true),
)
+ //TODO here is the place we want to place function to set country_code for ExitService,
+ // this function will be used in shared_app to setup the country_code for ExitService on startup
}
#[cfg(test)]
@@ -103,7 +114,7 @@ mod tests {
);
assert_eq!(
START_BLOCK_HELP,
- "Ordinal number of the Ethereum block where scanning for transactions will start."
+ "Ordinal number of the Ethereum block where scanning for transactions will start. Use 'latest' or 'none' for Latest block."
);
}
@@ -122,10 +133,28 @@ mod tests {
assert!(result.contains("cannot be used with one or more of the other specified arguments"));
}
+ #[test]
+ fn validate_start_block_catches_invalid_values() {
+ assert_eq!(validate_start_block("abc".to_string()), Err("Unable to parse 'abc' into a starting block number or provide 'none' or 'latest' for the latest block number: invalid digit found in string.".to_string()));
+ assert_eq!(validate_start_block("918446744073709551615".to_string()), Err("Unable to parse '918446744073709551615' into a starting block number or provide 'none' or 'latest' for the latest block number: digits exceed 18446744073709551615.".to_string()));
+ assert_eq!(validate_start_block("123,456,789".to_string()), Err("Unable to parse '123,456,789' into a starting block number or provide 'none' or 'latest' for the latest block number: invalid digit found in string.".to_string()));
+ assert_eq!(validate_start_block("123'456'789".to_string()), Err("Unable to parse '123'456'789' into a starting block number or provide 'none' or 'latest' for the latest block number: invalid digit found in string.".to_string()));
+ }
#[test]
fn validate_start_block_works() {
- assert!(validate_start_block("abc".to_string()).is_err());
- assert!(validate_start_block("1566".to_string()).is_ok());
+ assert_eq!(
+ validate_start_block("18446744073709551615".to_string()),
+ Ok(())
+ );
+ assert_eq!(validate_start_block("1566".to_string()), Ok(()));
+ assert_eq!(validate_start_block("none".to_string()), Ok(()));
+ assert_eq!(validate_start_block("None".to_string()), Ok(()));
+ assert_eq!(validate_start_block("NONE".to_string()), Ok(()));
+ assert_eq!(validate_start_block("nOnE".to_string()), Ok(()));
+ assert_eq!(validate_start_block("latest".to_string()), Ok(()));
+ assert_eq!(validate_start_block("LATEST".to_string()), Ok(()));
+ assert_eq!(validate_start_block("LaTeST".to_string()), Ok(()));
+ assert_eq!(validate_start_block("lATEst".to_string()), Ok(()));
}
#[test]
diff --git a/masq/src/commands/setup_command.rs b/masq/src/commands/setup_command.rs
index 92f605247..eaeede3c8 100644
--- a/masq/src/commands/setup_command.rs
+++ b/masq/src/commands/setup_command.rs
@@ -391,10 +391,10 @@ ip No sir, I don't like it.\n\
status_data_dir: UiSetupResponseValueStatus::Default,
},
SetupCommandData {
- chain_str: Some("polygon-mumbai".to_owned()),
+ chain_str: Some("polygon-amoy".to_owned()),
data_directory: None,
- chain_name_expected: Some("polygon-mumbai"),
- data_directory_expected: Some("/home/cooga/.local/MASQ/polygon-mumbai"),
+ chain_name_expected: Some("polygon-amoy"),
+ data_directory_expected: Some("/home/cooga/.local/MASQ/polygon-amoy"),
note_expected: true,
status_chain: UiSetupResponseValueStatus::Set,
status_data_dir: UiSetupResponseValueStatus::Default,
@@ -409,10 +409,10 @@ ip No sir, I don't like it.\n\
status_data_dir: UiSetupResponseValueStatus::Set,
},
SetupCommandData {
- chain_str: Some("polygon-mumbai".to_owned()),
- data_directory: Some("booga/polygon-mumbai".to_owned()),
- chain_name_expected: Some("polygon-mumbai"),
- data_directory_expected: Some("booga/polygon-mumbai/polygon-mumbai"),
+ chain_str: Some("polygon-amoy".to_owned()),
+ data_directory: Some("booga/polygon-amoy".to_owned()),
+ chain_name_expected: Some("polygon-amoy"),
+ data_directory_expected: Some("booga/polygon-amoy/polygon-amoy"),
note_expected: true,
status_chain: UiSetupResponseValueStatus::Set,
status_data_dir: UiSetupResponseValueStatus::Set,
diff --git a/masq/src/interactive_mode.rs b/masq/src/interactive_mode.rs
index a9141ffa5..026ed4aef 100644
--- a/masq/src/interactive_mode.rs
+++ b/masq/src/interactive_mode.rs
@@ -168,10 +168,11 @@ mod tests {
CommandFactoryMock, CommandProcessorMock, TerminalActiveMock, TerminalPassiveMock,
};
use crossbeam_channel::bounded;
- use masq_lib::test_utils::fake_stream_holder::{ByteArrayWriter, FakeStreamHolder};
+ use masq_lib::test_utils::fake_stream_holder::FakeStreamHolder;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
+ use test_utilities::byte_array_reader_writer::ByteArrayWriter;
#[test]
fn interactive_mode_works_for_unrecognized_command() {
diff --git a/masq/src/notifications/connection_change_notification.rs b/masq/src/notifications/connection_change_notification.rs
index 9ea7d5911..0480660fb 100644
--- a/masq/src/notifications/connection_change_notification.rs
+++ b/masq/src/notifications/connection_change_notification.rs
@@ -34,9 +34,9 @@ impl ConnectionChangeNotification {
mod tests {
use super::*;
use crate::test_utils::mocks::TerminalPassiveMock;
- use masq_lib::test_utils::fake_stream_holder::ByteArrayWriter;
use masq_lib::utils::running_test;
use std::sync::Arc;
+ use test_utilities::byte_array_reader_writer::ByteArrayWriter;
#[test]
fn broadcasts_connected_to_neighbor() {
diff --git a/masq/src/notifications/crashed_notification.rs b/masq/src/notifications/crashed_notification.rs
index 36e0ff4f4..66dfc773c 100644
--- a/masq/src/notifications/crashed_notification.rs
+++ b/masq/src/notifications/crashed_notification.rs
@@ -63,9 +63,9 @@ impl CrashNotifier {
mod tests {
use super::*;
use crate::test_utils::mocks::TerminalPassiveMock;
- use masq_lib::test_utils::fake_stream_holder::ByteArrayWriter;
use masq_lib::utils::running_test;
use std::sync::Arc;
+ use test_utilities::byte_array_reader_writer::ByteArrayWriter;
#[test]
pub fn handles_child_wait_failure() {
diff --git a/masq/src/schema.rs b/masq/src/schema.rs
index c03a3ea39..287fd9468 100644
--- a/masq/src/schema.rs
+++ b/masq/src/schema.rs
@@ -8,6 +8,7 @@ use crate::commands::configuration_command::configuration_subcommand;
use crate::commands::connection_status_command::connection_status_subcommand;
use crate::commands::crash_command::crash_subcommand;
use crate::commands::descriptor_command::descriptor_subcommand;
+use crate::commands::exit_location_command::exit_location_subcommand;
use crate::commands::financials_command::args_validation::financials_subcommand;
use crate::commands::generate_wallets_command::generate_wallets_subcommand;
use crate::commands::recover_wallets_command::recover_wallets_subcommand;
@@ -67,6 +68,7 @@ pub fn app() -> App<'static, 'static> {
.subcommand(configuration_subcommand())
.subcommand(connection_status_subcommand())
.subcommand(descriptor_subcommand())
+ .subcommand(exit_location_subcommand())
.subcommand(financials_subcommand())
.subcommand(generate_wallets_subcommand())
.subcommand(recover_wallets_subcommand())
diff --git a/masq/src/terminal/integration_test_utils.rs b/masq/src/terminal/integration_test_utils.rs
index 7f42f72f5..526e19a66 100644
--- a/masq/src/terminal/integration_test_utils.rs
+++ b/masq/src/terminal/integration_test_utils.rs
@@ -187,9 +187,9 @@ mod tests {
use crate::terminal::terminal_interface::TerminalWrapper;
use crate::test_utils::mocks::StdoutBlender;
use crossbeam_channel::{bounded, unbounded};
- use masq_lib::test_utils::fake_stream_holder::ByteArrayReader;
use std::thread;
use std::time::Duration;
+ use test_utilities::byte_array_reader_writer::ByteArrayReader;
#[test]
fn constants_have_correct_values() {
diff --git a/masq/src/test_utils/mocks.rs b/masq/src/test_utils/mocks.rs
index 955fa578a..9f70b7e5b 100644
--- a/masq/src/test_utils/mocks.rs
+++ b/masq/src/test_utils/mocks.rs
@@ -15,7 +15,6 @@ use linefeed::memory::MemoryTerminal;
use linefeed::{Interface, ReadResult, Signal};
use masq_lib::command::StdStreams;
use masq_lib::constants::DEFAULT_UI_PORT;
-use masq_lib::test_utils::fake_stream_holder::{ByteArrayWriter, ByteArrayWriterInner};
use masq_lib::ui_gateway::MessageBody;
use std::cell::RefCell;
use std::fmt::Arguments;
@@ -23,6 +22,7 @@ use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::{io, thread};
+use test_utilities::byte_array_reader_writer::{ByteArrayWriter, ByteArrayWriterInner};
pub const TRANSACT_TIMEOUT_MILLIS_FOR_TESTS: u64 = DEFAULT_TRANSACT_TIMEOUT_MILLIS;
diff --git a/masq_lib/Cargo.toml b/masq_lib/Cargo.toml
index f87de81a1..e845574a8 100644
--- a/masq_lib/Cargo.toml
+++ b/masq_lib/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "masq_lib"
-version = "0.8.0"
+version = "0.8.2"
authors = ["Dan Wiebe ", "MASQ"]
license = "GPL-3.0-only"
description = "Code common to Node and masq; also, temporarily, to dns_utility"
@@ -15,12 +15,14 @@ crossbeam-channel = "0.5.1"
dirs = "4.0.0"
ethereum-types = "0.9.0"
itertools = "0.10.1"
+ip_country = { path = "../ip_country"}
lazy_static = "1.4.0"
log = "0.4.8"
regex = "1.5.4"
serde = "1.0.133"
serde_derive = "1.0.133"
serde_json = "1.0.74"
+test_utilities = { path = "../test_utilities"}
time = {version = "0.3.11", features = [ "formatting" ]}
tiny-hderive = "0.3.0"
toml = "0.5.8"
diff --git a/masq_lib/src/blockchains/blockchain_records.rs b/masq_lib/src/blockchains/blockchain_records.rs
index f9b4bcab0..cc1198afa 100644
--- a/masq_lib/src/blockchains/blockchain_records.rs
+++ b/masq_lib/src/blockchains/blockchain_records.rs
@@ -2,16 +2,17 @@
use crate::blockchains::chains::Chain;
use crate::constants::{
- DEV_CHAIN_FULL_IDENTIFIER, ETH_MAINNET_CONTRACT_CREATION_BLOCK, ETH_MAINNET_FULL_IDENTIFIER,
- ETH_ROPSTEN_FULL_IDENTIFIER, MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK,
- MUMBAI_TESTNET_CONTRACT_CREATION_BLOCK, POLYGON_MAINNET_CONTRACT_CREATION_BLOCK,
- POLYGON_MAINNET_FULL_IDENTIFIER, POLYGON_MUMBAI_FULL_IDENTIFIER,
- ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK,
+ BASE_MAINNET_CONTRACT_CREATION_BLOCK, BASE_MAINNET_FULL_IDENTIFIER,
+ BASE_SEPOLIA_CONTRACT_CREATION_BLOCK, BASE_SEPOLIA_FULL_IDENTIFIER, DEV_CHAIN_FULL_IDENTIFIER,
+ ETH_MAINNET_CONTRACT_CREATION_BLOCK, ETH_MAINNET_FULL_IDENTIFIER,
+ ETH_ROPSTEN_CONTRACT_CREATION_BLOCK, ETH_ROPSTEN_FULL_IDENTIFIER,
+ MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK, POLYGON_AMOY_CONTRACT_CREATION_BLOCK,
+ POLYGON_AMOY_FULL_IDENTIFIER, POLYGON_MAINNET_CONTRACT_CREATION_BLOCK,
+ POLYGON_MAINNET_FULL_IDENTIFIER,
};
use ethereum_types::{Address, H160};
-//chains are ordered by their significance for the community of users (the order reflects in some error or help messages)
-pub const CHAINS: [BlockchainRecord; 5] = [
+pub const CHAINS: [BlockchainRecord; 7] = [
BlockchainRecord {
self_id: Chain::PolyMainnet,
num_chain_id: 137,
@@ -27,18 +28,32 @@ pub const CHAINS: [BlockchainRecord; 5] = [
contract_creation_block: ETH_MAINNET_CONTRACT_CREATION_BLOCK,
},
BlockchainRecord {
- self_id: Chain::PolyMumbai,
- num_chain_id: 80001,
- literal_identifier: POLYGON_MUMBAI_FULL_IDENTIFIER,
- contract: MUMBAI_TESTNET_CONTRACT_ADDRESS,
- contract_creation_block: MUMBAI_TESTNET_CONTRACT_CREATION_BLOCK,
+ self_id: Chain::BaseMainnet,
+ num_chain_id: 8453,
+ literal_identifier: BASE_MAINNET_FULL_IDENTIFIER,
+ contract: BASE_MAINNET_CONTRACT_ADDRESS,
+ contract_creation_block: BASE_MAINNET_CONTRACT_CREATION_BLOCK,
+ },
+ BlockchainRecord {
+ self_id: Chain::BaseSepolia,
+ num_chain_id: 84532,
+ literal_identifier: BASE_SEPOLIA_FULL_IDENTIFIER,
+ contract: BASE_SEPOLIA_TESTNET_CONTRACT_ADDRESS,
+ contract_creation_block: BASE_SEPOLIA_CONTRACT_CREATION_BLOCK,
+ },
+ BlockchainRecord {
+ self_id: Chain::PolyAmoy,
+ num_chain_id: 80002,
+ literal_identifier: POLYGON_AMOY_FULL_IDENTIFIER,
+ contract: POLYGON_AMOY_TESTNET_CONTRACT_ADDRESS,
+ contract_creation_block: POLYGON_AMOY_CONTRACT_CREATION_BLOCK,
},
BlockchainRecord {
self_id: Chain::EthRopsten,
num_chain_id: 3,
literal_identifier: ETH_ROPSTEN_FULL_IDENTIFIER,
- contract: ROPSTEN_TESTNET_CONTRACT_ADDRESS,
- contract_creation_block: ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK,
+ contract: ETH_ROPSTEN_TESTNET_CONTRACT_ADDRESS,
+ contract_creation_block: ETH_ROPSTEN_CONTRACT_CREATION_BLOCK,
},
BlockchainRecord {
self_id: Chain::Dev,
@@ -58,12 +73,28 @@ pub struct BlockchainRecord {
pub contract_creation_block: u64,
}
+// $tMASQ (Amoy)
+const POLYGON_AMOY_TESTNET_CONTRACT_ADDRESS: Address = H160([
+ 0xd9, 0x8c, 0x3e, 0xbd, 0x6b, 0x7f, 0x9b, 0x7c, 0xda, 0x24, 0x49, 0xec, 0xac, 0x00, 0xd1, 0xe5,
+ 0xf4, 0x7a, 0x81, 0x93,
+]);
+
// SHRD (Ropsten)
-const ROPSTEN_TESTNET_CONTRACT_ADDRESS: Address = H160([
+const ETH_ROPSTEN_TESTNET_CONTRACT_ADDRESS: Address = H160([
0x38, 0x4d, 0xec, 0x25, 0xe0, 0x3f, 0x94, 0x93, 0x17, 0x67, 0xce, 0x4c, 0x35, 0x56, 0x16, 0x84,
0x68, 0xba, 0x24, 0xc3,
]);
+const BASE_MAINNET_CONTRACT_ADDRESS: Address = H160([
+ 0x45, 0xD9, 0xC1, 0x01, 0xa3, 0x87, 0x0C, 0xa5, 0x02, 0x45, 0x82, 0xfd, 0x78, 0x8F, 0x4E, 0x1e,
+ 0x8F, 0x79, 0x71, 0xc3,
+]);
+
+const BASE_SEPOLIA_TESTNET_CONTRACT_ADDRESS: Address = H160([
+ 0x89, 0x8e, 0x1c, 0xe7, 0x20, 0x08, 0x4A, 0x90, 0x2b, 0xc3, 0x7d, 0xd8, 0x22, 0xed, 0x6d, 0x6a,
+ 0x5f, 0x02, 0x7e, 0x10,
+]);
+
const MULTINODE_TESTNET_CONTRACT_ADDRESS: Address = H160([
0x59, 0x88, 0x2e, 0x4a, 0x8f, 0x5d, 0x24, 0x64, 0x3d, 0x4d, 0xda, 0x42, 0x29, 0x22, 0xa8, 0x70,
0xf1, 0xb3, 0xe6, 0x64,
@@ -80,20 +111,11 @@ const POLYGON_MAINNET_CONTRACT_ADDRESS: Address = H160([
0xfB, 0xe9, 0xDd, 0x35,
]);
-// $tMASQ (Mumbai)
-#[allow(clippy::mixed_case_hex_literals)]
-const MUMBAI_TESTNET_CONTRACT_ADDRESS: Address = H160([
- 0x9B, 0x27, 0x03, 0x4a, 0xca, 0xBd, 0x44, 0x22, 0x3f, 0xB2, 0x3d, 0x62, 0x8B, 0xa4, 0x84, 0x98,
- 0x67, 0xcE, 0x1D, 0xB2,
-]);
-
#[cfg(test)]
mod tests {
use super::*;
use crate::blockchains::chains::chain_from_chain_identifier_opt;
- use crate::constants::{
- MUMBAI_TESTNET_CONTRACT_CREATION_BLOCK, POLYGON_MAINNET_CONTRACT_CREATION_BLOCK,
- };
+ use crate::constants::BASE_MAINNET_CONTRACT_CREATION_BLOCK;
use std::collections::HashSet;
use std::iter::FromIterator;
@@ -101,10 +123,12 @@ mod tests {
fn record_returns_correct_blockchain_record() {
let test_array = [
assert_returns_correct_record(Chain::EthMainnet, 1),
- assert_returns_correct_record(Chain::Dev, 2),
assert_returns_correct_record(Chain::EthRopsten, 3),
assert_returns_correct_record(Chain::PolyMainnet, 137),
- assert_returns_correct_record(Chain::PolyMumbai, 80001),
+ assert_returns_correct_record(Chain::PolyAmoy, 80002),
+ assert_returns_correct_record(Chain::BaseMainnet, 8453),
+ assert_returns_correct_record(Chain::BaseSepolia, 84532),
+ assert_returns_correct_record(Chain::Dev, 2),
];
assert_exhaustive(&test_array)
}
@@ -118,9 +142,11 @@ mod tests {
fn from_str_works() {
let test_array = [
assert_from_str(Chain::PolyMainnet),
- assert_from_str(Chain::PolyMumbai),
+ assert_from_str(Chain::PolyAmoy),
assert_from_str(Chain::EthMainnet),
assert_from_str(Chain::EthRopsten),
+ assert_from_str(Chain::BaseMainnet),
+ assert_from_str(Chain::BaseSepolia),
assert_from_str(Chain::Dev),
];
assert_exhaustive(&test_array)
@@ -140,18 +166,23 @@ mod tests {
#[test]
fn chains_are_ordered_by_their_significance_for_users() {
let test_array = [
- assert_chain_significance(0, Chain::PolyMainnet),
- assert_chain_significance(1, Chain::EthMainnet),
- assert_chain_significance(2, Chain::PolyMumbai),
- assert_chain_significance(3, Chain::EthRopsten),
- assert_chain_significance(4, Chain::Dev),
+ Chain::PolyMainnet,
+ Chain::EthMainnet,
+ Chain::BaseMainnet,
+ Chain::BaseSepolia,
+ Chain::PolyAmoy,
+ Chain::EthRopsten,
+ Chain::Dev,
];
+ test_array
+ .iter()
+ .enumerate()
+ .for_each(assert_chain_significance);
assert_exhaustive(&test_array)
}
- fn assert_chain_significance(idx: usize, chain: Chain) -> Chain {
- assert_eq!(CHAINS[idx].self_id, chain, "Error at index {}", idx);
- chain
+ fn assert_chain_significance((idx, chain): (usize, &Chain)) {
+ assert_eq!(CHAINS[idx].self_id, *chain, "Error at index {}", idx);
}
#[test]
@@ -180,8 +211,8 @@ mod tests {
num_chain_id: 3,
self_id: examined_chain,
literal_identifier: "eth-ropsten",
- contract: ROPSTEN_TESTNET_CONTRACT_ADDRESS,
- contract_creation_block: ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK,
+ contract: ETH_ROPSTEN_TESTNET_CONTRACT_ADDRESS,
+ contract_creation_block: ETH_ROPSTEN_CONTRACT_CREATION_BLOCK,
}
);
}
@@ -203,17 +234,49 @@ mod tests {
}
#[test]
- fn mumbai_record_is_properly_declared() {
- let examined_chain = Chain::PolyMumbai;
+ fn amoy_record_is_properly_declared() {
+ let examined_chain = Chain::PolyAmoy;
+ let chain_record = return_examined(examined_chain);
+ assert_eq!(
+ chain_record,
+ &BlockchainRecord {
+ num_chain_id: 80002,
+ self_id: examined_chain,
+ literal_identifier: "polygon-amoy",
+ contract: POLYGON_AMOY_TESTNET_CONTRACT_ADDRESS,
+ contract_creation_block: POLYGON_AMOY_CONTRACT_CREATION_BLOCK,
+ }
+ );
+ }
+
+ #[test]
+ fn base_mainnet_record_is_properly_declared() {
+ let examined_chain = Chain::BaseMainnet;
let chain_record = return_examined(examined_chain);
assert_eq!(
chain_record,
&BlockchainRecord {
- num_chain_id: 80001,
+ num_chain_id: 8453,
self_id: examined_chain,
- literal_identifier: "polygon-mumbai",
- contract: MUMBAI_TESTNET_CONTRACT_ADDRESS,
- contract_creation_block: MUMBAI_TESTNET_CONTRACT_CREATION_BLOCK,
+ literal_identifier: "base-mainnet",
+ contract: BASE_MAINNET_CONTRACT_ADDRESS,
+ contract_creation_block: BASE_MAINNET_CONTRACT_CREATION_BLOCK,
+ }
+ );
+ }
+
+ #[test]
+ fn base_sepolia_record_is_properly_declared() {
+ let examined_chain = Chain::BaseSepolia;
+ let chain_record = return_examined(examined_chain);
+ assert_eq!(
+ chain_record,
+ &BlockchainRecord {
+ num_chain_id: 84532,
+ self_id: examined_chain,
+ literal_identifier: "base-sepolia",
+ contract: BASE_SEPOLIA_TESTNET_CONTRACT_ADDRESS,
+ contract_creation_block: BASE_SEPOLIA_CONTRACT_CREATION_BLOCK,
}
);
}
@@ -229,7 +292,7 @@ mod tests {
self_id: examined_chain,
literal_identifier: "dev",
contract: MULTINODE_TESTNET_CONTRACT_ADDRESS,
- contract_creation_block: 0,
+ contract_creation_block: MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK,
}
);
}
@@ -243,9 +306,11 @@ mod tests {
let test_array = [
assert_chain_from_chain_identifier_opt("eth-mainnet", Some(Chain::EthMainnet)),
assert_chain_from_chain_identifier_opt("eth-ropsten", Some(Chain::EthRopsten)),
- assert_chain_from_chain_identifier_opt("dev", Some(Chain::Dev)),
assert_chain_from_chain_identifier_opt("polygon-mainnet", Some(Chain::PolyMainnet)),
- assert_chain_from_chain_identifier_opt("polygon-mumbai", Some(Chain::PolyMumbai)),
+ assert_chain_from_chain_identifier_opt("polygon-amoy", Some(Chain::PolyAmoy)),
+ assert_chain_from_chain_identifier_opt("base-mainnet", Some(Chain::BaseMainnet)),
+ assert_chain_from_chain_identifier_opt("base-sepolia", Some(Chain::BaseSepolia)),
+ assert_chain_from_chain_identifier_opt("dev", Some(Chain::Dev)),
];
assert_exhaustive(&test_array)
}
diff --git a/masq_lib/src/blockchains/chains.rs b/masq_lib/src/blockchains/chains.rs
index ac3fbbac0..b7733b842 100644
--- a/masq_lib/src/blockchains/chains.rs
+++ b/masq_lib/src/blockchains/chains.rs
@@ -2,8 +2,9 @@
use crate::blockchains::blockchain_records::{BlockchainRecord, CHAINS};
use crate::constants::{
- DEFAULT_CHAIN, DEV_CHAIN_FULL_IDENTIFIER, ETH_MAINNET_FULL_IDENTIFIER,
- ETH_ROPSTEN_FULL_IDENTIFIER, POLYGON_MAINNET_FULL_IDENTIFIER, POLYGON_MUMBAI_FULL_IDENTIFIER,
+ BASE_MAINNET_FULL_IDENTIFIER, BASE_SEPOLIA_FULL_IDENTIFIER, DEFAULT_CHAIN,
+ DEV_CHAIN_FULL_IDENTIFIER, ETH_MAINNET_FULL_IDENTIFIER, ETH_ROPSTEN_FULL_IDENTIFIER,
+ POLYGON_AMOY_FULL_IDENTIFIER, POLYGON_MAINNET_FULL_IDENTIFIER,
};
use serde_derive::{Deserialize, Serialize};
@@ -12,7 +13,9 @@ pub enum Chain {
EthMainnet,
EthRopsten,
PolyMainnet,
- PolyMumbai,
+ PolyAmoy,
+ BaseMainnet,
+ BaseSepolia,
Dev,
}
@@ -28,8 +31,12 @@ impl From<&str> for Chain {
Chain::PolyMainnet
} else if str == ETH_MAINNET_FULL_IDENTIFIER {
Chain::EthMainnet
- } else if str == POLYGON_MUMBAI_FULL_IDENTIFIER {
- Chain::PolyMumbai
+ } else if str == BASE_MAINNET_FULL_IDENTIFIER {
+ Chain::BaseMainnet
+ } else if str == BASE_SEPOLIA_FULL_IDENTIFIER {
+ Chain::BaseSepolia
+ } else if str == POLYGON_AMOY_FULL_IDENTIFIER {
+ Chain::PolyAmoy
} else if str == ETH_ROPSTEN_FULL_IDENTIFIER {
Chain::EthRopsten
} else if str == DEV_CHAIN_FULL_IDENTIFIER {
@@ -56,7 +63,7 @@ impl Chain {
}
fn mainnets() -> &'static [Chain] {
- &[Chain::PolyMainnet, Chain::EthMainnet]
+ &[Chain::PolyMainnet, Chain::BaseMainnet, Chain::EthMainnet]
}
}
diff --git a/masq_lib/src/constants.rs b/masq_lib/src/constants.rs
index 7bdcbe1e1..03b3a4c88 100644
--- a/masq_lib/src/constants.rs
+++ b/masq_lib/src/constants.rs
@@ -5,7 +5,7 @@ use crate::data_version::DataVersion;
use const_format::concatcp;
pub const DEFAULT_CHAIN: Chain = Chain::PolyMainnet;
-pub const CURRENT_SCHEMA_VERSION: usize = 9;
+pub const CURRENT_SCHEMA_VERSION: usize = 10;
pub const HIGHEST_RANDOM_CLANDESTINE_PORT: u16 = 9999;
pub const HTTP_PORT: u16 = 80;
@@ -24,11 +24,15 @@ pub const WALLET_ADDRESS_LENGTH: usize = 42;
pub const MASQ_TOTAL_SUPPLY: u64 = 37_500_000;
pub const WEIS_IN_GWEI: i128 = 1_000_000_000;
+pub const DEFAULT_MAX_BLOCK_COUNT: u64 = 100_000;
+
pub const ETH_MAINNET_CONTRACT_CREATION_BLOCK: u64 = 11_170_708;
-pub const ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK: u64 = 8_688_171;
-pub const MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK: u64 = 0;
+pub const ETH_ROPSTEN_CONTRACT_CREATION_BLOCK: u64 = 8_688_171;
pub const POLYGON_MAINNET_CONTRACT_CREATION_BLOCK: u64 = 14_863_650;
-pub const MUMBAI_TESTNET_CONTRACT_CREATION_BLOCK: u64 = 24_638_838;
+pub const POLYGON_AMOY_CONTRACT_CREATION_BLOCK: u64 = 5_323_366;
+pub const BASE_MAINNET_CONTRACT_CREATION_BLOCK: u64 = 19_711_235;
+pub const BASE_SEPOLIA_CONTRACT_CREATION_BLOCK: u64 = 14_732_730;
+pub const MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK: u64 = 0;
//Migration versions
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -71,6 +75,7 @@ pub const UNMARSHAL_ERROR: u64 = UI_NODE_COMMUNICATION_PREFIX | 4;
pub const SETUP_ERROR: u64 = UI_NODE_COMMUNICATION_PREFIX | 5;
pub const TIMEOUT_ERROR: u64 = UI_NODE_COMMUNICATION_PREFIX | 6;
pub const SCAN_ERROR: u64 = UI_NODE_COMMUNICATION_PREFIX | 7;
+pub const EXIT_COUNTRY_ERROR: u64 = UI_NODE_COMMUNICATION_PREFIX | 8;
//accountant
pub const ACCOUNTANT_PREFIX: u64 = 0x0040_0000_0000_0000;
@@ -87,15 +92,18 @@ pub const CENTRAL_DELIMITER: char = '@';
pub const CHAIN_IDENTIFIER_DELIMITER: char = ':';
//chains
-const MAINNET: &str = "mainnet";
const POLYGON_FAMILY: &str = "polygon";
const ETH_FAMILY: &str = "eth";
+const BASE_FAMILY: &str = "base";
+const MAINNET: &str = "mainnet";
const LINK: char = '-';
pub const POLYGON_MAINNET_FULL_IDENTIFIER: &str = concatcp!(POLYGON_FAMILY, LINK, MAINNET);
-pub const POLYGON_MUMBAI_FULL_IDENTIFIER: &str = concatcp!(POLYGON_FAMILY, LINK, "mumbai");
-pub const DEV_CHAIN_FULL_IDENTIFIER: &str = "dev";
+pub const POLYGON_AMOY_FULL_IDENTIFIER: &str = concatcp!(POLYGON_FAMILY, LINK, "amoy");
pub const ETH_MAINNET_FULL_IDENTIFIER: &str = concatcp!(ETH_FAMILY, LINK, MAINNET);
pub const ETH_ROPSTEN_FULL_IDENTIFIER: &str = concatcp!(ETH_FAMILY, LINK, "ropsten");
+pub const BASE_MAINNET_FULL_IDENTIFIER: &str = concatcp!(BASE_FAMILY, LINK, MAINNET);
+pub const BASE_SEPOLIA_FULL_IDENTIFIER: &str = concatcp!(BASE_FAMILY, LINK, "sepolia");
+pub const DEV_CHAIN_FULL_IDENTIFIER: &str = "dev";
#[cfg(test)]
mod tests {
@@ -118,10 +126,12 @@ mod tests {
assert_eq!(MASQ_TOTAL_SUPPLY, 37_500_000);
assert_eq!(WEIS_IN_GWEI, 1_000_000_000);
assert_eq!(ETH_MAINNET_CONTRACT_CREATION_BLOCK, 11_170_708);
- assert_eq!(ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK, 8_688_171);
- assert_eq!(MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK, 0);
+ assert_eq!(ETH_ROPSTEN_CONTRACT_CREATION_BLOCK, 8_688_171);
assert_eq!(POLYGON_MAINNET_CONTRACT_CREATION_BLOCK, 14_863_650);
- assert_eq!(MUMBAI_TESTNET_CONTRACT_CREATION_BLOCK, 24_638_838);
+ assert_eq!(POLYGON_AMOY_CONTRACT_CREATION_BLOCK, 5_323_366);
+ assert_eq!(BASE_MAINNET_CONTRACT_CREATION_BLOCK, 19_711_235);
+ assert_eq!(BASE_SEPOLIA_CONTRACT_CREATION_BLOCK, 14_732_730);
+ assert_eq!(MULTINODE_TESTNET_CONTRACT_CREATION_BLOCK, 0);
assert_eq!(CONFIGURATOR_PREFIX, 0x0001_0000_0000_0000);
assert_eq!(CONFIGURATOR_READ_ERROR, CONFIGURATOR_PREFIX | 1);
assert_eq!(CONFIGURATOR_WRITE_ERROR, CONFIGURATOR_PREFIX | 2);
@@ -157,15 +167,17 @@ mod tests {
assert_eq!(VALUE_EXCEEDS_ALLOWED_LIMIT, ACCOUNTANT_PREFIX | 3);
assert_eq!(CENTRAL_DELIMITER, '@');
assert_eq!(CHAIN_IDENTIFIER_DELIMITER, ':');
- assert_eq!(MAINNET, "mainnet");
assert_eq!(POLYGON_FAMILY, "polygon");
assert_eq!(ETH_FAMILY, "eth");
+ assert_eq!(BASE_FAMILY, "base");
+ assert_eq!(MAINNET, "mainnet");
assert_eq!(LINK, '-');
assert_eq!(POLYGON_MAINNET_FULL_IDENTIFIER, "polygon-mainnet");
- assert_eq!(POLYGON_MUMBAI_FULL_IDENTIFIER, "polygon-mumbai");
- assert_eq!(DEV_CHAIN_FULL_IDENTIFIER, "dev");
+ assert_eq!(POLYGON_AMOY_FULL_IDENTIFIER, "polygon-amoy");
assert_eq!(ETH_MAINNET_FULL_IDENTIFIER, "eth-mainnet");
assert_eq!(ETH_ROPSTEN_FULL_IDENTIFIER, "eth-ropsten");
+ assert_eq!(BASE_SEPOLIA_FULL_IDENTIFIER, "base-sepolia");
+ assert_eq!(DEV_CHAIN_FULL_IDENTIFIER, "dev");
assert_eq!(
CLIENT_REQUEST_PAYLOAD_CURRENT_VERSION,
DataVersion { major: 0, minor: 1 }
diff --git a/masq_lib/src/messages.rs b/masq_lib/src/messages.rs
index 59522171e..5821d62a3 100644
--- a/masq_lib/src/messages.rs
+++ b/masq_lib/src/messages.rs
@@ -492,7 +492,7 @@ pub struct UiConfigurationResponse {
#[serde(rename = "portMappingProtocol")]
pub port_mapping_protocol_opt: Option,
#[serde(rename = "startBlock")]
- pub start_block: u64,
+ pub start_block_opt: Option,
#[serde(rename = "consumingWalletPrivateKeyOpt")]
pub consuming_wallet_private_key_opt: Option,
// This item is calculated from the private key, not stored in the database, so that
@@ -846,6 +846,44 @@ pub struct UiWalletAddressesResponse {
}
conversation_message!(UiWalletAddressesResponse, "walletAddresses");
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct CountryCodes {
+ #[serde(rename = "countryCodes")]
+ pub country_codes: Vec,
+ #[serde(rename = "priority")]
+ pub priority: usize,
+}
+
+impl From<(String, usize)> for CountryCodes {
+ fn from((item, priority): (String, usize)) -> Self {
+ CountryCodes {
+ country_codes: item
+ .split(',')
+ .into_iter()
+ .map(|x| x.to_string())
+ .collect::>(),
+ priority: priority + 1,
+ }
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct UiSetExitLocationRequest {
+ #[serde(rename = "fallbackRouting")]
+ pub fallback_routing: bool,
+ #[serde(rename = "exitLocations")]
+ pub exit_locations: Vec,
+ #[serde(rename = "showCountries")]
+ pub show_countries: bool,
+}
+
+conversation_message!(UiSetExitLocationRequest, "exitLocation");
+
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct UiSetExitLocationResponse {}
+
+conversation_message!(UiSetExitLocationResponse, "exitLocation");
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/masq_lib/src/shared_schema.rs b/masq_lib/src/shared_schema.rs
index fc7e8ced2..9bd948e8d 100644
--- a/masq_lib/src/shared_schema.rs
+++ b/masq_lib/src/shared_schema.rs
@@ -1,9 +1,10 @@
// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
use crate::constants::{
- DEFAULT_GAS_PRICE, DEFAULT_UI_PORT, DEV_CHAIN_FULL_IDENTIFIER, ETH_MAINNET_FULL_IDENTIFIER,
- ETH_ROPSTEN_FULL_IDENTIFIER, HIGHEST_USABLE_PORT, LOWEST_USABLE_INSECURE_PORT,
- POLYGON_MAINNET_FULL_IDENTIFIER, POLYGON_MUMBAI_FULL_IDENTIFIER,
+ BASE_MAINNET_FULL_IDENTIFIER, BASE_SEPOLIA_FULL_IDENTIFIER, DEFAULT_GAS_PRICE, DEFAULT_UI_PORT,
+ DEV_CHAIN_FULL_IDENTIFIER, ETH_MAINNET_FULL_IDENTIFIER, ETH_ROPSTEN_FULL_IDENTIFIER,
+ HIGHEST_USABLE_PORT, LOWEST_USABLE_INSECURE_PORT, POLYGON_AMOY_FULL_IDENTIFIER,
+ POLYGON_MAINNET_FULL_IDENTIFIER,
};
use crate::crash_point::CrashPoint;
use clap::{App, Arg};
@@ -13,6 +14,7 @@ pub const BLOCKCHAIN_SERVICE_HELP: &str =
"The Ethereum client you wish to use to provide Blockchain \
exit services from your MASQ Node (e.g. http://localhost:8545, \
https://ropsten.infura.io/v3/YOUR-PROJECT-ID, https://mainnet.infura.io/v3/YOUR-PROJECT-ID), \
+ https://base-mainnet.g.alchemy.com/v2/d66UL0lPrltmweEqVsv3opBSVI3wkL8I, \
https://polygon-mainnet.infura.io/v3/YOUR-PROJECT-ID";
pub const CHAIN_HELP: &str =
"The blockchain network MASQ Node will configure itself to use. You must ensure the \
@@ -64,8 +66,9 @@ pub const NEIGHBORS_HELP: &str = "One or more Node descriptors for running Nodes
on startup. A Node descriptor looks similar to one of these:\n\n\
masq://polygon-mainnet:d2U3Dv1BqtS5t_Zz3mt9_sCl7AgxUlnkB4jOMElylrU@172.50.48.6:9342\n\
masq://eth-mainnet:gBviQbjOS3e5ReFQCvIhUM3i02d1zPleo1iXg_EN6zQ@86.75.30.9:5542\n\
- masq://polygon-mumbai:A6PGHT3rRjaeFpD_rFi3qGEXAVPq7bJDfEUZpZaIyq8@14.10.50.6:10504\n\
- masq://eth-ropsten:OHsC2CAm4rmfCkaFfiynwxflUgVTJRb2oY5mWxNCQkY@150.60.42.72:6642/4789/5254\n\n\
+ masq://base-mainnet:ZjPLnb9RrgsRM1D9edqH8jx9DkbPZSWqqFqLnmdKhsk@112.55.78.0:7878\n\
+ masq://polygon-amoy:A6PGHT3rRjaeFpD_rFi3qGEXAVPq7bJDfEUZpZaIyq8@14.10.50.6:10504\n\
+ masq://base-sepolia:OHsC2CAm4rmfCkaFfiynwxflUgVTJRb2oY5mWxNCQkY@150.60.42.72:6642/4789/5254\n\n\
Notice each of the different chain identifiers in the masq protocol prefix - they determine a family of chains \
and also the network the descriptor belongs to (mainnet or a testnet). See also the last descriptor which shows \
a configuration with multiple clandestine ports.\n\n\
@@ -256,7 +259,9 @@ pub fn official_chain_names() -> &'static [&'static str] {
&[
POLYGON_MAINNET_FULL_IDENTIFIER,
ETH_MAINNET_FULL_IDENTIFIER,
- POLYGON_MUMBAI_FULL_IDENTIFIER,
+ BASE_MAINNET_FULL_IDENTIFIER,
+ BASE_SEPOLIA_FULL_IDENTIFIER,
+ POLYGON_AMOY_FULL_IDENTIFIER,
ETH_ROPSTEN_FULL_IDENTIFIER,
DEV_CHAIN_FULL_IDENTIFIER,
]
@@ -388,7 +393,6 @@ pub fn shared_app(head: App<'static, 'static>) -> App<'static, 'static> {
.case_insensitive(true)
.hidden(true),
)
- .arg(data_directory_arg(DATA_DIRECTORY_HELP))
.arg(db_password_arg(DB_PASSWORD_HELP))
.arg(
Arg::with_name("dns-servers")
@@ -484,6 +488,7 @@ pub fn shared_app(head: App<'static, 'static>) -> App<'static, 'static> {
pub mod common_validators {
use crate::constants::LOWEST_USABLE_INSECURE_PORT;
+ use ip_country_lib::countries::INDEX_BY_ISO3166;
use regex::Regex;
use std::net::IpAddr;
use std::str::FromStr;
@@ -520,6 +525,44 @@ pub mod common_validators {
}
}
+ pub fn validate_country_code(country_code: &str) -> Result<(), String> {
+ match INDEX_BY_ISO3166.contains_key(country_code) {
+ true => Ok(()),
+ false => Err(format!(
+ "'{}' is not a valid ISO3166 country code",
+ country_code
+ )),
+ }
+ }
+
+ pub fn validate_exit_locations(exit_location: String) -> Result<(), String> {
+ validate_pipe_separated_values(exit_location, |country: String| {
+ let mut collect_fails = "".to_string();
+ country.split(',').into_iter().for_each(|country_code| {
+ match validate_country_code(country_code) {
+ Ok(_) => (),
+ Err(e) => collect_fails.push_str(&e),
+ }
+ });
+ match collect_fails.is_empty() {
+ true => Ok(()),
+ false => Err(collect_fails),
+ }
+ })
+ }
+
+ pub fn validate_separate_u64_values(values: String) -> Result<(), String> {
+ validate_pipe_separated_values(values, |segment: String| {
+ segment
+ .parse::()
+ .map_err(|_| {
+ "Supply nonnegative numeric values separated by vertical bars like 111|222|333|..."
+ .to_string()
+ })
+ .map(|_| ())
+ })
+ }
+
pub fn validate_private_key(key: String) -> Result<(), String> {
if Regex::new("^[0-9a-fA-F]{64}$")
.expect("Failed to compile regular expression")
@@ -606,16 +649,24 @@ pub mod common_validators {
}
}
- pub fn validate_separate_u64_values(values_with_delimiters: String) -> Result<(), String> {
- values_with_delimiters.split('|').try_for_each(|segment| {
- segment
- .parse::()
- .map_err(|_| {
- "Supply positive numeric values separated by vertical bars like 111|222|333|..."
- .to_string()
- })
- .map(|_| ())
- })
+ fn validate_pipe_separated_values(
+ values_with_delimiters: String,
+ closure: fn(String) -> Result<(), String>,
+ ) -> Result<(), String> {
+ let mut error_collection = vec![];
+ values_with_delimiters
+ .split('|')
+ .into_iter()
+ .for_each(|segment| {
+ match closure(segment.to_string()) {
+ Ok(_) => (),
+ Err(msg) => error_collection.push(msg),
+ };
+ });
+ match error_collection.is_empty() {
+ true => Ok(()),
+ false => Err(error_collection.into_iter().collect::()),
+ }
}
}
@@ -670,11 +721,11 @@ impl ConfiguratorError {
#[cfg(test)]
mod tests {
-
use super::*;
use crate::blockchains::chains::Chain;
use crate::shared_schema::common_validators::validate_non_zero_u16;
use crate::shared_schema::{common_validators, official_chain_names};
+ use std::collections::HashSet;
#[test]
fn constants_have_correct_values() {
@@ -683,6 +734,7 @@ mod tests {
"The Ethereum client you wish to use to provide Blockchain \
exit services from your MASQ Node (e.g. http://localhost:8545, \
https://ropsten.infura.io/v3/YOUR-PROJECT-ID, https://mainnet.infura.io/v3/YOUR-PROJECT-ID), \
+ https://base-mainnet.g.alchemy.com/v2/d66UL0lPrltmweEqVsv3opBSVI3wkL8I, \
https://polygon-mainnet.infura.io/v3/YOUR-PROJECT-ID"
);
assert_eq!(
@@ -757,8 +809,9 @@ mod tests {
on startup. A Node descriptor looks similar to one of these:\n\n\
masq://polygon-mainnet:d2U3Dv1BqtS5t_Zz3mt9_sCl7AgxUlnkB4jOMElylrU@172.50.48.6:9342\n\
masq://eth-mainnet:gBviQbjOS3e5ReFQCvIhUM3i02d1zPleo1iXg_EN6zQ@86.75.30.9:5542\n\
- masq://polygon-mumbai:A6PGHT3rRjaeFpD_rFi3qGEXAVPq7bJDfEUZpZaIyq8@14.10.50.6:10504\n\
- masq://eth-ropsten:OHsC2CAm4rmfCkaFfiynwxflUgVTJRb2oY5mWxNCQkY@150.60.42.72:6642/4789/5254\n\n\
+ masq://base-mainnet:ZjPLnb9RrgsRM1D9edqH8jx9DkbPZSWqqFqLnmdKhsk@112.55.78.0:7878\n\
+ masq://polygon-amoy:A6PGHT3rRjaeFpD_rFi3qGEXAVPq7bJDfEUZpZaIyq8@14.10.50.6:10504\n\
+ masq://base-sepolia:OHsC2CAm4rmfCkaFfiynwxflUgVTJRb2oY5mWxNCQkY@150.60.42.72:6642/4789/5254\n\n\
Notice each of the different chain identifiers in the masq protocol prefix - they determine a family of chains \
and also the network the descriptor belongs to (mainnet or a testnet). See also the last descriptor which shows \
a configuration with multiple clandestine ports.\n\n\
@@ -925,6 +978,23 @@ mod tests {
)
}
+ #[test]
+ fn validate_exit_key_fails_on_not_valid_country_code() {
+ let result = common_validators::validate_exit_locations(String::from("CZ|SK,RR"));
+
+ assert_eq!(
+ result,
+ Err("'RR' is not a valid ISO3166 country code".to_string())
+ );
+ }
+
+ #[test]
+ fn validate_exit_key_success() {
+ let result = common_validators::validate_exit_locations(String::from("CZ|SK"));
+
+ assert_eq!(result, Ok(()));
+ }
+
#[test]
fn validate_private_key_requires_a_key_that_is_64_characters_long() {
let result = common_validators::validate_private_key(String::from("42"));
@@ -1075,7 +1145,7 @@ mod tests {
assert_eq!(
result,
Err(String::from(
- "Supply positive numeric values separated by vertical bars like 111|222|333|..."
+ "Supply nonnegative numeric values separated by vertical bars like 111|222|333|..."
))
)
}
@@ -1087,7 +1157,7 @@ mod tests {
assert_eq!(
result,
Err(String::from(
- "Supply positive numeric values separated by vertical bars like 111|222|333|..."
+ "Supply nonnegative numeric values separated by vertical bars like 111|222|333|..."
))
)
}
@@ -1099,7 +1169,7 @@ mod tests {
assert_eq!(
result,
Err(String::from(
- "Supply positive numeric values separated by vertical bars like 111|222|333|..."
+ "Supply nonnegative numeric values separated by vertical bars like 111|222|333|..."
))
)
}
@@ -1141,12 +1211,34 @@ mod tests {
#[test]
fn official_chain_names_are_reliable() {
- let mut iterator = official_chain_names().iter();
- assert_eq!(Chain::from(*iterator.next().unwrap()), Chain::PolyMainnet);
- assert_eq!(Chain::from(*iterator.next().unwrap()), Chain::EthMainnet);
- assert_eq!(Chain::from(*iterator.next().unwrap()), Chain::PolyMumbai);
- assert_eq!(Chain::from(*iterator.next().unwrap()), Chain::EthRopsten);
- assert_eq!(Chain::from(*iterator.next().unwrap()), Chain::Dev);
- assert_eq!(iterator.next(), None)
+ let expected_supported_chains = [
+ Chain::PolyMainnet,
+ Chain::EthMainnet,
+ Chain::BaseMainnet,
+ Chain::BaseSepolia,
+ Chain::PolyAmoy,
+ Chain::EthRopsten,
+ Chain::Dev,
+ ]
+ .into_iter()
+ .collect::>();
+
+ let chain_names_recognizable_by_clap = official_chain_names();
+
+ let chains_from_clap = chain_names_recognizable_by_clap
+ .into_iter()
+ .map(|chain_name| Chain::from(*chain_name))
+ .collect::>();
+ let differences = chains_from_clap
+ .symmetric_difference(&expected_supported_chains)
+ .collect::>();
+ assert!(
+ differences.is_empty(),
+ "There are differences in the Clap schema in the collection of supported chains, \
+ between the expected values {:?} and actual {:?}, specifically {:?}",
+ expected_supported_chains,
+ chains_from_clap,
+ differences
+ );
}
}
diff --git a/masq_lib/src/test_utils/fake_stream_holder.rs b/masq_lib/src/test_utils/fake_stream_holder.rs
index d971ffa7a..d57ed3c3c 100644
--- a/masq_lib/src/test_utils/fake_stream_holder.rs
+++ b/masq_lib/src/test_utils/fake_stream_holder.rs
@@ -1,136 +1,7 @@
// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
use crate::command::StdStreams;
-use std::cmp::min;
-use std::io;
-use std::io::Read;
-use std::io::Write;
-use std::io::{BufRead, Error};
-use std::sync::{Arc, Mutex};
-
-pub struct ByteArrayWriter {
- inner_arc: Arc>,
-}
-
-pub struct ByteArrayWriterInner {
- byte_array: Vec,
- next_error: Option,
-}
-
-impl ByteArrayWriterInner {
- pub fn get_bytes(&self) -> Vec {
- self.byte_array.clone()
- }
- pub fn get_string(&self) -> String {
- String::from_utf8(self.get_bytes()).unwrap()
- }
-}
-
-impl Default for ByteArrayWriter {
- fn default() -> Self {
- ByteArrayWriter {
- inner_arc: Arc::new(Mutex::new(ByteArrayWriterInner {
- byte_array: vec![],
- next_error: None,
- })),
- }
- }
-}
-
-impl ByteArrayWriter {
- pub fn new() -> ByteArrayWriter {
- Self::default()
- }
-
- pub fn inner_arc(&self) -> Arc> {
- self.inner_arc.clone()
- }
-
- pub fn get_bytes(&self) -> Vec {
- self.inner_arc.lock().unwrap().byte_array.clone()
- }
- pub fn get_string(&self) -> String {
- String::from_utf8(self.get_bytes()).unwrap()
- }
-
- pub fn reject_next_write(&mut self, error: Error) {
- self.inner_arc().lock().unwrap().next_error = Some(error);
- }
-}
-
-impl Write for ByteArrayWriter {
- fn write(&mut self, buf: &[u8]) -> io::Result {
- let mut inner = self.inner_arc.lock().unwrap();
- if let Some(next_error) = inner.next_error.take() {
- Err(next_error)
- } else {
- for byte in buf {
- inner.byte_array.push(*byte)
- }
- Ok(buf.len())
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-pub struct ByteArrayReader {
- byte_array: Vec,
- position: usize,
- next_error: Option,
-}
-
-impl ByteArrayReader {
- pub fn new(byte_array: &[u8]) -> ByteArrayReader {
- ByteArrayReader {
- byte_array: byte_array.to_vec(),
- position: 0,
- next_error: None,
- }
- }
-
- pub fn reject_next_read(mut self, error: Error) -> ByteArrayReader {
- self.next_error = Some(error);
- self
- }
-}
-
-impl Read for ByteArrayReader {
- fn read(&mut self, buf: &mut [u8]) -> io::Result {
- match self.next_error.take() {
- Some(error) => Err(error),
- None => {
- let to_copy = min(buf.len(), self.byte_array.len() - self.position);
- #[allow(clippy::needless_range_loop)]
- for idx in 0..to_copy {
- buf[idx] = self.byte_array[self.position + idx]
- }
- self.position += to_copy;
- Ok(to_copy)
- }
- }
- }
-}
-
-impl BufRead for ByteArrayReader {
- fn fill_buf(&mut self) -> io::Result<&[u8]> {
- match self.next_error.take() {
- Some(error) => Err(error),
- None => Ok(&self.byte_array[self.position..]),
- }
- }
-
- fn consume(&mut self, amt: usize) {
- let result = self.position + amt;
- self.position = if result < self.byte_array.len() {
- result
- } else {
- self.byte_array.len()
- }
- }
-}
+use test_utilities::byte_array_reader_writer::{ByteArrayReader, ByteArrayWriter};
pub struct FakeStreamHolder {
pub stdin: ByteArrayReader,
diff --git a/masq_lib/src/test_utils/logging.rs b/masq_lib/src/test_utils/logging.rs
index ec60ea72f..92566a753 100644
--- a/masq_lib/src/test_utils/logging.rs
+++ b/masq_lib/src/test_utils/logging.rs
@@ -1,6 +1,5 @@
// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
use crate::logger::real_format_function;
-use crate::test_utils::fake_stream_holder::ByteArrayWriter;
use crate::test_utils::utils::to_millis;
use lazy_static::lazy_static;
use log::set_logger;
@@ -13,6 +12,7 @@ use std::sync::{Arc, Mutex, MutexGuard};
use std::thread;
use std::time::Duration;
use std::time::Instant;
+use test_utilities::byte_array_reader_writer::ByteArrayWriter;
use time::OffsetDateTime;
lazy_static! {
diff --git a/masq_lib/src/test_utils/utils.rs b/masq_lib/src/test_utils/utils.rs
index ac12bd6ab..6d1e12609 100644
--- a/masq_lib/src/test_utils/utils.rs
+++ b/masq_lib/src/test_utils/utils.rs
@@ -35,8 +35,16 @@ pub fn ensure_node_home_directory_exists(module: &str, name: &str) -> PathBuf {
}
pub fn is_running_under_github_actions() -> bool {
- if let Ok(value) = std::env::var("GITHUB_ACTIONS") {
- &value == "true"
+ is_env_variable_set("GITHUB_ACTIONS", "true")
+}
+
+pub fn is_test_generated_data_allowed_to_escape_project_dir() -> bool {
+ is_env_variable_set("ALLOW_TEST_DATA_ESCAPE_PROJECT_DIR", "true")
+}
+
+fn is_env_variable_set(var_name: &str, searched_value: &str) -> bool {
+ if let Ok(value) = std::env::var(var_name) {
+ value == searched_value
} else {
false
}
diff --git a/masq_lib/src/utils.rs b/masq_lib/src/utils.rs
index 1083af2b9..8d563ef37 100644
--- a/masq_lib/src/utils.rs
+++ b/masq_lib/src/utils.rs
@@ -49,14 +49,14 @@ fn compute_data_directory_help() -> String {
let polygon_mainnet_dir = Path::new(&data_dir.to_str().unwrap())
.join("MASQ")
.join("polygon-mainnet");
- let polygon_mumbai_dir = Path::new(&data_dir.to_str().unwrap())
+ let polygon_amoy_dir = Path::new(&data_dir.to_str().unwrap())
.join("MASQ")
- .join("polygon-mumbai");
+ .join("polygon-amoy");
format!("Directory in which the Node will store its persistent state, including at least its database \
and by default its configuration file as well. By default, your data-directory is located in \
your application directory, under your home directory e.g.: '{}'.\n\n\
In case you change your chain to a different one, the data-directory path is automatically changed \
- to end with the name of your chain: e.g.: if you choose polygon-mumbai, then data-directory is \
+ to end with the name of your chain: e.g.: if you choose polygon-amoy, then data-directory is \
automatically changed to: '{}'.\n\n\
You can specify your own data-directory to the Daemon in two different ways: \n\n\
1. If you provide a path without the chain name on the end, the Daemon will automatically change \
@@ -65,7 +65,7 @@ fn compute_data_directory_help() -> String {
2. If you provide your data directory with the corresponding chain name on the end, eg: {}/masq_home/polygon-mainnet, \
there will be no change until you set the chain parameter to a different value.",
polygon_mainnet_dir.to_string_lossy().to_string().as_str(),
- polygon_mumbai_dir.to_string_lossy().to_string().as_str(),
+ polygon_amoy_dir.to_string_lossy().to_string().as_str(),
&home_dir.to_string_lossy().to_string().as_str(),
&home_dir.to_string_lossy().to_string().as_str(),
home_dir.to_string_lossy().to_string().as_str()
diff --git a/multinode_integration_tests/Cargo.toml b/multinode_integration_tests/Cargo.toml
index bf50f472f..775ee0306 100644
--- a/multinode_integration_tests/Cargo.toml
+++ b/multinode_integration_tests/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "multinode_integration_tests"
-version = "0.8.0"
+version = "0.8.2"
authors = ["Dan Wiebe ", "MASQ"]
license = "GPL-3.0-only"
description = ""
diff --git a/multinode_integration_tests/docker/blockchain/Dockerfile b/multinode_integration_tests/docker/blockchain/Dockerfile
index 027eb7a27..7ff65ea16 100644
--- a/multinode_integration_tests/docker/blockchain/Dockerfile
+++ b/multinode_integration_tests/docker/blockchain/Dockerfile
@@ -1,8 +1,8 @@
# Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
-FROM trufflesuite/ganache-cli:v6.7.0
+FROM trufflesuite/ganache-cli:v6.12.2
ADD ./entrypoint.sh /app/
EXPOSE 18545
-ENTRYPOINT /app/entrypoint.sh
+ENTRYPOINT ["/app/entrypoint.sh"]
diff --git a/multinode_integration_tests/docker/blockchain/entrypoint.sh b/multinode_integration_tests/docker/blockchain/entrypoint.sh
index f9d6cc220..c184cbb50 100755
--- a/multinode_integration_tests/docker/blockchain/entrypoint.sh
+++ b/multinode_integration_tests/docker/blockchain/entrypoint.sh
@@ -1,3 +1,8 @@
#!/bin/sh
-node /app/ganache-core.docker.cli.js -p 18545 --networkId 2 --verbose --mnemonic "timber cage wide hawk phone shaft pattern movie army dizzy hen tackle lamp absent write kind term toddler sphere ripple idle dragon curious hold"
+node /app/ganache-core.docker.cli.js \
+ -h 0.0.0.0 \
+ -p 18545 \
+ --networkId 2 \
+ --verbose \
+ --mnemonic "timber cage wide hawk phone shaft pattern movie army dizzy hen tackle lamp absent write kind term toddler sphere ripple idle dragon curious hold"
diff --git a/multinode_integration_tests/src/main.rs b/multinode_integration_tests/src/main.rs
index d78421672..8f705fed9 100644
--- a/multinode_integration_tests/src/main.rs
+++ b/multinode_integration_tests/src/main.rs
@@ -1,11 +1,10 @@
// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
-use self::sub_lib::utils::indicates_dead_stream;
use masq_lib::command::{Command, StdStreams};
use masq_lib::constants::{HIGHEST_USABLE_PORT, LOWEST_USABLE_INSECURE_PORT};
-use node_lib::sub_lib;
use node_lib::sub_lib::framer::Framer;
use node_lib::sub_lib::node_addr::NodeAddr;
+use node_lib::sub_lib::utils::indicates_dead_stream;
use node_lib::test_utils::data_hunk::DataHunk;
use node_lib::test_utils::data_hunk_framer::DataHunkFramer;
use std::borrow::BorrowMut;
@@ -14,10 +13,9 @@ use std::env;
use std::io;
use std::io::Read;
use std::io::Write;
-use std::net::Shutdown;
-use std::net::SocketAddr;
use std::net::TcpListener;
use std::net::TcpStream;
+use std::net::{Shutdown, SocketAddr};
use std::process;
use std::str::FromStr;
use std::sync::{Arc, Mutex, MutexGuard};
@@ -223,10 +221,10 @@ impl MockNode {
}
fn usage(stderr: &mut dyn Write) -> u8 {
- writeln! (stderr, "Usage: MockNode ://... where is the address MockNode is running on and is between {} and {}",
- LOWEST_USABLE_INSECURE_PORT,
- HIGHEST_USABLE_PORT,
- ).unwrap ();
+ writeln!(stderr, "Usage: MockNode ://... where is the address MockNode is running on and is between {} and {}",
+ LOWEST_USABLE_INSECURE_PORT,
+ HIGHEST_USABLE_PORT,
+ ).unwrap();
1
}
@@ -369,7 +367,7 @@ mod tests {
assert_eq!(result, 1);
let stderr = holder.stderr;
- assert_eq! (stderr.get_string (), String::from ("Usage: MockNode ://... where is the address MockNode is running on and is between 1025 and 65535\n\n"));
+ assert_eq!(stderr.get_string(), String::from("Usage: MockNode ://... where is the address MockNode is running on and is between 1025 and 65535\n\n"));
}
#[test]
diff --git a/multinode_integration_tests/src/masq_node_cluster.rs b/multinode_integration_tests/src/masq_node_cluster.rs
index 86a94af54..aff6f1d37 100644
--- a/multinode_integration_tests/src/masq_node_cluster.rs
+++ b/multinode_integration_tests/src/masq_node_cluster.rs
@@ -337,6 +337,43 @@ impl MASQNodeCluster {
)),
}
}
+
+ #[allow(dead_code)]
+ fn interconnect_world_network(network_one: &str, network_two: &str) -> Result<(), String> {
+ let mut command = Command::new(
+ "docker",
+ Command::strings(vec!["network", "connect", network_one, network_two]),
+ );
+ match command.wait_for_exit() {
+ 0 => Ok(()),
+ _ => Err(format!(
+ "Could not connect network {} to {}: {}",
+ network_one,
+ network_two,
+ command.stderr_as_string()
+ )),
+ }
+ }
+
+ #[allow(dead_code)]
+ fn create_world_network(ipv4addr: Ipv4Addr, name: &str) -> Result<(), String> {
+ let mut command = Command::new(
+ "docker",
+ Command::strings(vec![
+ "network",
+ "create",
+ format!("--subnet={}/16", ipv4addr).as_str(),
+ name,
+ ]),
+ );
+ match command.wait_for_exit() {
+ 0 => Ok(()),
+ _ => Err(format!(
+ "Could not create network integration_net: {}",
+ command.stderr_as_string()
+ )),
+ }
+ }
}
pub struct DockerHostSocketAddr {
diff --git a/multinode_integration_tests/src/mock_blockchain_client_server.rs b/multinode_integration_tests/src/mock_blockchain_client_server.rs
index 24031b2cc..a40543808 100644
--- a/multinode_integration_tests/src/mock_blockchain_client_server.rs
+++ b/multinode_integration_tests/src/mock_blockchain_client_server.rs
@@ -241,8 +241,10 @@ impl MockBlockchainClientServer {
let mut requests = requests_arc.lock().unwrap();
requests.push(body);
}
- let response = responses.remove(0);
- Self::send_body(conn_state, response);
+ if !responses.is_empty() {
+ let response = responses.remove(0);
+ Self::send_body(conn_state, response);
+ }
let _ = notifier_tx.send(()); // receiver doesn't exist if test didn't set it up
}
None => (),
@@ -437,7 +439,7 @@ mod tests {
.response("Thank you and good night", 40)
.start();
let mut client = connect(port);
- client.write (b"POST /biddle HTTP/1.1\r\nContent-Length: 5\r\n\r\nfirstPOST /biddle HTTP/1.1\r\nContent-Length: 6\r\n\r\nsecond").unwrap();
+ client.write(b"POST /biddle HTTP/1.1\r\nContent-Length: 5\r\n\r\nfirstPOST /biddle HTTP/1.1\r\nContent-Length: 6\r\n\r\nsecond").unwrap();
let (_, body) = receive_response(&mut client);
assert_eq!(
@@ -567,7 +569,7 @@ mod tests {
assert_eq!(notified.try_recv().is_err(), true);
let requests = subject.requests();
- assert_eq! (requests, vec! [
+ assert_eq!(requests, vec![
"POST /biddle HTTP/1.1\r\nContent-Type: application-json\r\nContent-Length: 82\r\n\r\n{\"jsonrpc\": \"2.0\", \"method\": \"first\", \"params\": [\"biddle\", \"de\", \"bee\"], \"id\": 40}".to_string(),
"POST /biddle HTTP/1.1\r\nContent-Type: application-json\r\nContent-Length: 48\r\n\r\n{\"jsonrpc\": \"2.0\", \"method\": \"second\", \"id\": 42}".to_string(),
"POST /biddle HTTP/1.1\r\nContent-Type: application-json\r\nContent-Length: 47\r\n\r\n{\"jsonrpc\": \"2.0\", \"method\": \"third\", \"id\": 42}".to_string(),
@@ -600,7 +602,7 @@ mod tests {
r#"{"jsonrpc": "2.0", "result": {"name":"Billy","age":15}, "id": 42}"#
);
let requests = subject.requests();
- assert_eq! (requests, vec! [
+ assert_eq!(requests, vec![
"POST / HTTP/1.1\r\ncontent-type: application/json\r\nuser-agent: web3.rs\r\nhost: 172.18.0.1:32768\r\ncontent-length: 308\r\n\r\n{\"jsonrpc\":\"2.0\",\"method\":\"eth_getLogs\",\"params\":[{\"address\":\"0x59882e4a8f5d24643d4dda422922a870f1b3e664\",\"fromBlock\":\"0x3e8\",\"toBlock\":\"latest\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",null,\"0x00000000000000000000000027d9a2ac83b493f88ce9b4532edcf74e95b9788d\"]}],\"id\":0}".to_string()
])
}
@@ -704,6 +706,6 @@ mod tests {
body.len(),
body
)
- .into_bytes()
+ .into_bytes()
}
}
diff --git a/multinode_integration_tests/src/neighborhood_constructor.rs b/multinode_integration_tests/src/neighborhood_constructor.rs
index ba3fb650b..53a9d611e 100644
--- a/multinode_integration_tests/src/neighborhood_constructor.rs
+++ b/multinode_integration_tests/src/neighborhood_constructor.rs
@@ -259,8 +259,8 @@ fn from_masq_node_to_node_record(masq_node: &dyn MASQNode) -> NodeRecord {
last_update: time_t_timestamp(),
node_addr_opt: agr.node_addr_opt.clone(),
unreachable_hosts: Default::default(),
- node_distrust_score: 0,
node_location_opt: None,
+ country_undesirability: 0u32,
},
signed_gossip: agr.signed_gossip.clone(),
signature: agr.signature,
diff --git a/multinode_integration_tests/src/utils.rs b/multinode_integration_tests/src/utils.rs
index 6c4868e89..5c522b364 100644
--- a/multinode_integration_tests/src/utils.rs
+++ b/multinode_integration_tests/src/utils.rs
@@ -3,7 +3,6 @@
use crate::command::Command;
use crate::masq_node::{MASQNode, MASQNodeUtils};
use crate::masq_real_node::MASQRealNode;
-use ip_country_lib::country_finder::COUNTRY_CODE_FINDER;
use masq_lib::test_utils::utils::TEST_DEFAULT_MULTINODE_CHAIN;
use masq_lib::utils::NeighborhoodModeLight;
use node_lib::accountant::db_access_objects::payable_dao::{PayableDao, PayableDaoReal};
@@ -147,7 +146,7 @@ impl From<&dyn MASQNode> for AccessibleGossipRecord {
signature: CryptData::new(b""),
};
let ip_addr = masq_node.node_addr().ip_addr();
- let country_code = get_node_location(Some(ip_addr), &COUNTRY_CODE_FINDER);
+ let country_code = get_node_location(Some(ip_addr));
if let Some(cc) = country_code {
agr.inner.country_code_opt = Some(cc.country_code)
};
diff --git a/multinode_integration_tests/tests/blockchain_interaction_test.rs b/multinode_integration_tests/tests/blockchain_interaction_test.rs
index bb7c00578..a675dcd76 100644
--- a/multinode_integration_tests/tests/blockchain_interaction_test.rs
+++ b/multinode_integration_tests/tests/blockchain_interaction_test.rs
@@ -5,7 +5,6 @@ use std::path::PathBuf;
use std::time::{Duration, SystemTime};
use log::Level;
-use regex::escape;
use serde_derive::Serialize;
use masq_lib::messages::{FromMessageBody, ScanType, ToMessageBody, UiScanRequest, UiScanResponse};
@@ -161,19 +160,15 @@ fn blockchain_bridge_starts_properly_on_bootstrap() {
let mut cluster = MASQNodeCluster::start().unwrap();
let private_key = "0011223300112233001122330011223300112233001122330011223300112233";
let subject = cluster.start_real_node(
- NodeStartupConfigBuilder::zero_hop()
+ NodeStartupConfigBuilder::standard()
.consuming_wallet_info(ConsumingWalletInfo::PrivateKey(private_key.to_string()))
.chain(cluster.chain)
.build(),
);
- let escaped_pattern = escape(&format!(
- "DEBUG: BlockchainBridge: Received BindMessage; consuming wallet address {}",
- subject.consuming_wallet().unwrap()
- ));
MASQNodeUtils::wrote_log_containing(
subject.name(),
- &escaped_pattern,
+ "DEBUG: BlockchainBridge: Received BindMessage",
Duration::from_millis(1000),
)
}
diff --git a/multinode_integration_tests/tests/data_routing_test.rs b/multinode_integration_tests/tests/data_routing_test.rs
index 0b3fa9d21..cdefcd354 100644
--- a/multinode_integration_tests/tests/data_routing_test.rs
+++ b/multinode_integration_tests/tests/data_routing_test.rs
@@ -316,7 +316,7 @@ fn multiple_stream_zero_hop_test() {
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 /online/ HTTP/1.1\r\nHost: whatever.neverssl.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");
let one_response = one_client.wait_for_chunk();
let another_response = another_client.wait_for_chunk();
@@ -330,7 +330,8 @@ fn multiple_stream_zero_hop_test() {
assert_eq!(
index_of(
&another_response,
- &b"neverssl.com will never use SSL (also known as TLS)"[..],
+ &b"This is an index url which gives an overview of the different test urls available."
+ [..],
)
.is_some(),
true,
diff --git a/multinode_integration_tests/tests/verify_bill_payment.rs b/multinode_integration_tests/tests/verify_bill_payment.rs
index 5e9b50347..1240deb58 100644
--- a/multinode_integration_tests/tests/verify_bill_payment.rs
+++ b/multinode_integration_tests/tests/verify_bill_payment.rs
@@ -38,10 +38,7 @@ use web3::Web3;
#[test]
fn verify_bill_payment() {
- let mut cluster = match MASQNodeCluster::start() {
- Ok(cluster) => cluster,
- Err(e) => panic!("{}", e),
- };
+ let mut cluster = MASQNodeCluster::start().unwrap();
let blockchain_server = BlockchainServer {
name: "ganache-cli",
};
@@ -64,7 +61,7 @@ fn verify_bill_payment() {
assert_balances(
&contract_owner_wallet,
&blockchain_interface,
- "99998043204000000000",
+ "99998381140000000000",
"472000000000000000000000000",
);
let payment_thresholds = PaymentThresholds {
@@ -189,7 +186,7 @@ fn verify_bill_payment() {
assert_balances(
&contract_owner_wallet,
&blockchain_interface,
- "99998043204000000000",
+ "99998381140000000000",
"472000000000000000000000000",
);
@@ -235,7 +232,7 @@ fn verify_bill_payment() {
assert_balances(
&contract_owner_wallet,
&blockchain_interface,
- "99997886466000000000",
+ "99998223682000000000",
"471999999700000000000000000",
);
@@ -330,7 +327,7 @@ fn assert_balances(
assert_eq!(
format!("{}", eth_balance),
String::from(expected_eth_balance),
- "Actual EthBalance {} doesn't much with expected {}",
+ "Actual EthBalance {} doesn't match with expected {}",
eth_balance,
expected_eth_balance
);
diff --git a/node/Cargo.lock b/node/Cargo.lock
index 5d4b6605d..16e936902 100644
--- a/node/Cargo.lock
+++ b/node/Cargo.lock
@@ -182,7 +182,7 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "automap"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"crossbeam-channel 0.5.1",
"flexi_logger 0.17.1",
@@ -1565,7 +1565,7 @@ dependencies = [
"csv",
"itertools 0.13.0",
"lazy_static",
- "masq_lib",
+ "test_utilities",
]
[[package]]
@@ -1842,7 +1842,7 @@ dependencies = [
[[package]]
name = "masq"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"atty",
"clap",
@@ -1855,6 +1855,7 @@ dependencies = [
"nix 0.23.1",
"num",
"regex",
+ "test_utilities",
"thousands",
"time 0.3.11",
"websocket",
@@ -1862,7 +1863,7 @@ dependencies = [
[[package]]
name = "masq_lib"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"actix",
"clap",
@@ -1870,6 +1871,7 @@ dependencies = [
"crossbeam-channel 0.5.1",
"dirs 4.0.0",
"ethereum-types",
+ "ip_country",
"itertools 0.10.3",
"lazy_static",
"log 0.4.18",
@@ -1878,6 +1880,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
+ "test_utilities",
"time 0.3.11",
"tiny-hderive",
"toml",
@@ -2039,7 +2042,7 @@ dependencies = [
[[package]]
name = "multinode_integration_tests"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"base64 0.13.0",
"crossbeam-channel 0.5.1",
@@ -2133,7 +2136,7 @@ dependencies = [
[[package]]
name = "node"
-version = "0.8.0"
+version = "0.8.2"
dependencies = [
"actix",
"automap",
@@ -2188,6 +2191,7 @@ dependencies = [
"sodiumoxide",
"sysinfo",
"system-configuration",
+ "test_utilities",
"thousands",
"time 0.3.11",
"tiny-bip39",
@@ -3654,6 +3658,10 @@ dependencies = [
"phf_codegen",
]
+[[package]]
+name = "test_utilities"
+version = "0.1.0"
+
[[package]]
name = "textwrap"
version = "0.11.0"
diff --git a/node/Cargo.toml b/node/Cargo.toml
index 345daa234..552761f32 100644
--- a/node/Cargo.toml
+++ b/node/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "node"
-version = "0.8.0"
+version = "0.8.2"
license = "GPL-3.0-only"
authors = ["Dan Wiebe ", "MASQ"]
description = "MASQ Node is the foundation of MASQ Network, an open-source network that allows anyone to allocate spare computing resources to make the internet a free and fair place for the entire world."
@@ -86,6 +86,7 @@ native-tls = {version = "0.2.8", features = ["vendored"]}
simple-server = "0.4.0"
serial_test_derive = "0.5.1"
serial_test = "0.5.1"
+test_utilities = { path = "../test_utilities"}
trust-dns-proto = "0.8.0"
[[bin]]
diff --git a/node/docs/Blockchain-Service.md b/node/docs/Blockchain-Service.md
index 4f6e407cb..eb930736f 100644
--- a/node/docs/Blockchain-Service.md
+++ b/node/docs/Blockchain-Service.md
@@ -2,7 +2,7 @@
### What is a blockchain service URL?
-A blockchain service url is a URL that MASQ Node uses to interact with various blockchains, either the Mumbai and Ropsten
+A blockchain service url is a URL that MASQ Node uses to interact with various blockchains, either the Amoy and Ropsten
testnets or Polygon and Ethereum mainnets. On mainnets, MASQ uses the MASQ token; on testnets, it uses a test token.
#### MASQ Node software supports connections to the following blockchains:
@@ -11,7 +11,7 @@ testnets or Polygon and Ethereum mainnets. On mainnets, MASQ uses the MASQ token
- [x] Ethereum mainnet
**Polygon**
-- [x] Mumbai testnet
+- [x] Amoy testnet
- [x] Polygon mainnet *in beta testing*
To be fully functional MASQ Node needs communication to the blockchain for access to:
@@ -29,27 +29,27 @@ There are two general types of Blockchain Services MASQ Node currently supports.
### 1. Sign up for a free [Infura.io](https://infura.io/register) account.
Follow the instructions here [Infura.io/docs](https://infura.io/docs) to create a "Project"
-Choose one of the following options for the network of your choice (if you are testing it is likely the Mumbai testnet):
+Choose one of the following options for the network of your choice (if you are testing it is likely the Amoy testnet):
-* Enter your Infura.io url `https://polygon-mumbai.infura.io/v3/` in the blockchain service url field of the GUI.
+* Enter your Infura.io url `https://polygon-amoy.infura.io/v3/` in the blockchain service url field of the GUI.
* For the `masq` command-line interface, use the `setup` command:
- > `masq> setup --blockchain-service-url https://polygon-mumbai.infura.io/v3/`
+ > `masq> setup --blockchain-service-url https://polygon-amoy.infura.io/v3/`
* Edit your config.toml file and include the entry
- > `blockservice-service-url = "https://polygon-mumbai.infura.io/v3/"`
+ > `blockservice-service-url = "https://polygon-amoy.infura.io/v3/"`
* Or define an environment variable
* Windows
- > `set MASQ_BLOCKCHAIN_SERVICE_URL = https://polygon-mumbai.infura.io/v3/`
+ > `set MASQ_BLOCKCHAIN_SERVICE_URL = https://polygon-amoy.infura.io/v3/`
* Linux or macOS
- > `export MASQ_BLOCKCHAIN_SERVICE_URL = https://polygon-mumbai.infura.io/v3/`
+ > `export MASQ_BLOCKCHAIN_SERVICE_URL = https://polygon-amoy.infura.io/v3/`
Change `` with the PROJECT ID from your Infura.io Project Dashboard. Change the URL to
mainnet when ready to spend and earn real MASQ.
diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs
index bd444ef8f..e76b15a0d 100644
--- a/node/src/accountant/mod.rs
+++ b/node/src/accountant/mod.rs
@@ -25,7 +25,7 @@ use crate::accountant::financials::visibility_restricted_module::{
use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::msgs::{
BlockchainAgentWithContextMessage, QualifiedPayablesMessage,
};
-use crate::accountant::scanners::{ScanSchedulers, Scanners};
+use crate::accountant::scanners::{BeginScanError, ScanSchedulers, Scanners};
use crate::blockchain::blockchain_bridge::{
PendingPayableFingerprint, PendingPayableFingerprintSeeds, RetrieveTransactions,
};
@@ -43,6 +43,7 @@ use crate::sub_lib::accountant::ReportRoutingServiceProvidedMessage;
use crate::sub_lib::accountant::ReportServicesConsumedMessage;
use crate::sub_lib::accountant::{MessageIdGenerator, MessageIdGeneratorReal};
use crate::sub_lib::blockchain_bridge::OutboundPaymentsInstructions;
+use crate::sub_lib::neighborhood::{ConfigChange, ConfigChangeMsg};
use crate::sub_lib::peer_actors::{BindMessage, StartMessage};
use crate::sub_lib::utils::{handle_ui_crash_request, NODE_MAILBOX_CAPACITY};
use crate::sub_lib::wallet::Wallet;
@@ -83,7 +84,7 @@ pub const DEFAULT_PENDING_TOO_LONG_SEC: u64 = 21_600; //6 hours
pub struct Accountant {
suppress_initial_scans: bool,
consuming_wallet_opt: Option,
- earning_wallet: Rc,
+ earning_wallet: Wallet,
payable_dao: Box,
receivable_dao: Box,
pending_payable_dao: Box,
@@ -164,6 +165,14 @@ impl Handler for Accountant {
}
}
+impl Handler for Accountant {
+ type Result = ();
+
+ fn handle(&mut self, msg: ConfigChangeMsg, _ctx: &mut Self::Context) -> Self::Result {
+ self.handle_config_change_msg(msg);
+ }
+}
+
impl Handler for Accountant {
type Result = ();
@@ -408,7 +417,7 @@ impl Accountant {
pub fn new(config: BootstrapperConfig, dao_factories: DaoFactories) -> Accountant {
let payment_thresholds = config.payment_thresholds_opt.expectv("Payment thresholds");
let scan_intervals = config.scan_intervals_opt.expectv("Scan Intervals");
- let earning_wallet = Rc::new(config.earning_wallet);
+ let earning_wallet = config.earning_wallet.clone();
let financial_statistics = Rc::new(RefCell::new(FinancialStatistics::default()));
let payable_dao = dao_factories.payable_dao_factory.make();
let pending_payable_dao = dao_factories.pending_payable_dao_factory.make();
@@ -416,7 +425,6 @@ impl Accountant {
let scanners = Scanners::new(
dao_factories,
Rc::new(payment_thresholds),
- Rc::clone(&earning_wallet),
config.when_pending_too_long_sec,
Rc::clone(&financial_statistics),
);
@@ -424,7 +432,7 @@ impl Accountant {
Accountant {
suppress_initial_scans: config.suppress_initial_scans,
consuming_wallet_opt: config.consuming_wallet_opt.clone(),
- earning_wallet: Rc::clone(&earning_wallet),
+ earning_wallet,
payable_dao,
receivable_dao,
pending_payable_dao,
@@ -447,6 +455,7 @@ impl Accountant {
pub fn make_subs_from(addr: &Addr) -> AccountantSubs {
AccountantSubs {
bind: recipient!(addr, BindMessage),
+ config_change_msg_sub: recipient!(addr, ConfigChangeMsg),
start: recipient!(addr, StartMessage),
report_routing_service_provided: recipient!(addr, ReportRoutingServiceProvidedMessage),
report_exit_service_provided: recipient!(addr, ReportExitServiceProvidedMessage),
@@ -563,6 +572,27 @@ impl Accountant {
info!(self.logger, "Accountant bound");
}
+ fn handle_config_change_msg(&mut self, msg: ConfigChangeMsg) {
+ if let ConfigChange::UpdateWallets(wallet_pair) = msg.change {
+ if self.earning_wallet != wallet_pair.earning_wallet {
+ info!(
+ self.logger,
+ "Earning Wallet has been updated: {}", wallet_pair.earning_wallet
+ );
+ self.earning_wallet = wallet_pair.earning_wallet;
+ }
+ if self.consuming_wallet_opt != Some(wallet_pair.consuming_wallet.clone()) {
+ info!(
+ self.logger,
+ "Consuming Wallet has been updated: {}", wallet_pair.consuming_wallet
+ );
+ self.consuming_wallet_opt = Some(wallet_pair.consuming_wallet);
+ }
+ } else {
+ trace!(self.logger, "Ignored irrelevant message: {:?}", msg);
+ }
+ }
+
fn schedule_next_scan(&self, scan_type: ScanType, ctx: &mut Context) {
self.scan_schedulers
.schedulers
@@ -806,11 +836,17 @@ impl Accountant {
&mut self,
response_skeleton_opt: Option,
) {
- match self.scanners.payable.begin_scan(
- SystemTime::now(),
- response_skeleton_opt,
- &self.logger,
- ) {
+ let result = match self.consuming_wallet_opt.clone() {
+ Some(consuming_wallet) => self.scanners.payable.begin_scan(
+ consuming_wallet,
+ SystemTime::now(),
+ response_skeleton_opt,
+ &self.logger,
+ ),
+ None => Err(BeginScanError::NoConsumingWalletFound),
+ };
+
+ match result {
Ok(scan_message) => {
self.qualified_payables_sub_opt
.as_ref()
@@ -830,11 +866,17 @@ impl Accountant {
&mut self,
response_skeleton_opt: Option,
) {
- match self.scanners.pending_payable.begin_scan(
- SystemTime::now(),
- response_skeleton_opt,
- &self.logger,
- ) {
+ let result = match self.consuming_wallet_opt.clone() {
+ Some(consuming_wallet) => self.scanners.pending_payable.begin_scan(
+ consuming_wallet, // This argument is not used and is therefore irrelevant
+ SystemTime::now(),
+ response_skeleton_opt,
+ &self.logger,
+ ),
+ None => Err(BeginScanError::NoConsumingWalletFound),
+ };
+
+ match result {
Ok(scan_message) => self
.request_transaction_receipts_subs_opt
.as_ref()
@@ -854,6 +896,7 @@ impl Accountant {
response_skeleton_opt: Option,
) {
match self.scanners.receivable.begin_scan(
+ self.earning_wallet.clone(),
SystemTime::now(),
response_skeleton_opt,
&self.logger,
@@ -1013,6 +1056,7 @@ mod tests {
use crate::blockchain::test_utils::{make_tx_hash, BlockchainInterfaceMock};
use crate::database::rusqlite_wrappers::TransactionSafeWrapper;
use crate::database::test_utils::transaction_wrapper_mock::TransactionInnerWrapperMockBuilder;
+ use crate::db_config::config_dao::ConfigDaoRecord;
use crate::db_config::mocks::ConfigDaoMock;
use crate::match_every_type_id;
use crate::sub_lib::accountant::{
@@ -1020,6 +1064,8 @@ mod tests {
DEFAULT_EARNING_WALLET, DEFAULT_PAYMENT_THRESHOLDS,
};
use crate::sub_lib::blockchain_bridge::OutboundPaymentsInstructions;
+ use crate::sub_lib::neighborhood::ConfigChange;
+ use crate::sub_lib::neighborhood::{Hops, WalletPair};
use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock;
use crate::test_utils::recorder::make_recorder;
use crate::test_utils::recorder::peer_actors_builder;
@@ -1196,7 +1242,7 @@ mod tests {
default_scan_intervals.receivable_scan_interval,
);
assert_eq!(result.consuming_wallet_opt, None);
- assert_eq!(*result.earning_wallet, *DEFAULT_EARNING_WALLET);
+ assert_eq!(result.earning_wallet, *DEFAULT_EARNING_WALLET);
assert_eq!(result.suppress_initial_scans, false);
result
.message_id_generator
@@ -1208,6 +1254,68 @@ mod tests {
assert_eq!(financial_statistics.total_paid_payable_wei, 0);
}
+ #[test]
+ fn accountant_handles_config_change_msg() {
+ assert_handling_of_config_change_msg(
+ ConfigChangeMsg {
+ change: ConfigChange::UpdateWallets(WalletPair {
+ consuming_wallet: make_paying_wallet(b"new_consuming_wallet"),
+ earning_wallet: make_wallet("new_earning_wallet"),
+ }),
+ },
+ |subject: &Accountant| {
+ assert_eq!(
+ subject.consuming_wallet_opt,
+ Some(make_paying_wallet(b"new_consuming_wallet"))
+ );
+ assert_eq!(subject.earning_wallet, make_wallet("new_earning_wallet"));
+ let _ = TestLogHandler::new().assert_logs_contain_in_order(
+ vec![
+ "INFO: ConfigChange: Earning Wallet has been updated: 0x00006e65775f6561726e696e675f77616c6c6574",
+ "INFO: ConfigChange: Consuming Wallet has been updated: 0xfa133bbf90bce093fa2e7caa6da68054af66793e",
+ ]
+ );
+ },
+ );
+ assert_handling_of_config_change_msg(
+ ConfigChangeMsg {
+ change: ConfigChange::UpdatePassword("new password".to_string()),
+ },
+ |_subject: &Accountant| {
+ let _ = TestLogHandler::new().exists_log_containing(
+ "TRACE: ConfigChange: Ignored irrelevant message: \
+ ConfigChangeMsg { change: UpdatePassword(\"new password\") }",
+ );
+ },
+ );
+ assert_handling_of_config_change_msg(
+ ConfigChangeMsg {
+ change: ConfigChange::UpdateMinHops(Hops::FourHops),
+ },
+ |_subject: &Accountant| {
+ let _ = TestLogHandler::new().exists_log_containing(
+ "TRACE: ConfigChange: Ignored irrelevant message: \
+ ConfigChangeMsg { change: UpdateMinHops(FourHops) }",
+ );
+ },
+ );
+ }
+
+ fn assert_handling_of_config_change_msg(msg: ConfigChangeMsg, assertions: A)
+ where
+ A: FnOnce(&Accountant),
+ {
+ init_test_logging();
+ let mut subject = AccountantBuilder::default()
+ .bootstrapper_config(make_bc_with_defaults())
+ .build();
+ subject.logger = Logger::new("ConfigChange");
+
+ subject.handle_config_change_msg(msg);
+
+ assertions(&subject);
+ }
+
#[test]
fn scan_receivables_request() {
let mut config = bc_from_earning_wallet(make_wallet("earning_wallet"));
@@ -1266,7 +1374,11 @@ mod tests {
config.suppress_initial_scans = true;
let subject = AccountantBuilder::default()
.bootstrapper_config(config)
- .config_dao(ConfigDaoMock::new().set_result(Ok(())))
+ .config_dao(
+ ConfigDaoMock::new()
+ .get_result(Ok(ConfigDaoRecord::new("start_block", None, false)))
+ .set_result(Ok(())),
+ )
.build();
let (ui_gateway, _, ui_gateway_recording_arc) = make_recorder();
let subject_addr = subject.start();
@@ -1300,6 +1412,7 @@ mod tests {
#[test]
fn scan_payables_request() {
let config = bc_from_earning_wallet(make_wallet("some_wallet_address"));
+ let consuming_wallet = make_paying_wallet(b"consuming");
let payable_account = PayableAccount {
wallet: make_wallet("wallet"),
balance_wei: gwei_to_wei(DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1),
@@ -1312,6 +1425,7 @@ mod tests {
PayableDaoMock::new().non_pending_payables_result(vec![payable_account.clone()]);
let subject = AccountantBuilder::default()
.bootstrapper_config(config)
+ .consuming_wallet(consuming_wallet.clone())
.payable_daos(vec![ForPayableScanner(payable_dao)])
.build();
let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder();
@@ -1338,6 +1452,7 @@ mod tests {
blockchain_bridge_recording.get_record::(0),
&QualifiedPayablesMessage {
protected_qualified_payables: protect_payables_in_test(vec![payable_account]),
+ consuming_wallet,
response_skeleton_opt: Some(ResponseSkeleton {
client_id: 1234,
context_id: 4321,
@@ -1617,6 +1732,7 @@ mod tests {
let pending_payable_dao = PendingPayableDaoMock::default()
.return_all_errorless_fingerprints_result(vec![fingerprint.clone()]);
let subject = AccountantBuilder::default()
+ .consuming_wallet(make_paying_wallet(b"consuming"))
.bootstrapper_config(config)
.pending_payable_daos(vec![ForPendingPayableScanner(pending_payable_dao)])
.build();
@@ -1675,6 +1791,7 @@ mod tests {
.return_all_errorless_fingerprints_result(vec![fingerprint]);
let subject = AccountantBuilder::default()
.bootstrapper_config(config)
+ .consuming_wallet(make_paying_wallet(b"consuming"))
.logger(Logger::new(test_name))
.pending_payable_daos(vec![ForPendingPayableScanner(pending_payable_dao)])
.build();
@@ -1802,8 +1919,10 @@ mod tests {
let system = System::new(
"accountant_sends_initial_payable_payments_msg_when_qualified_payable_found",
);
+ let consuming_wallet = make_paying_wallet(b"consuming");
let mut subject = AccountantBuilder::default()
.bootstrapper_config(bc_from_earning_wallet(make_wallet("some_wallet_address")))
+ .consuming_wallet(consuming_wallet.clone())
.payable_daos(vec![ForPayableScanner(payable_dao)])
.build();
subject.scanners.pending_payable = Box::new(NullScanner::new());
@@ -1826,6 +1945,7 @@ mod tests {
message,
&QualifiedPayablesMessage {
protected_qualified_payables: protect_payables_in_test(qualified_payables),
+ consuming_wallet,
response_skeleton_opt: None,
}
);
@@ -1876,6 +1996,7 @@ mod tests {
) {
let more_money_received_params_arc = Arc::new(Mutex::new(vec![]));
let commit_params_arc = Arc::new(Mutex::new(vec![]));
+ let get_params_arc = Arc::new(Mutex::new(vec![]));
let set_by_guest_transaction_params_arc = Arc::new(Mutex::new(vec![]));
let now = SystemTime::now();
let earning_wallet = make_wallet("earner3000");
@@ -1899,6 +2020,8 @@ mod tests {
.more_money_received_params(&more_money_received_params_arc)
.more_money_received_result(wrapped_transaction);
let config_dao = ConfigDaoMock::new()
+ .get_params(&get_params_arc)
+ .get_result(Ok(ConfigDaoRecord::new("start_block", None, false)))
.set_by_guest_transaction_params(&set_by_guest_transaction_params_arc)
.set_by_guest_transaction_result(Ok(()));
let accountant = AccountantBuilder::default()
@@ -1913,7 +2036,7 @@ mod tests {
.try_send(ReceivedPayments {
timestamp: now,
payments: vec![expected_receivable_1.clone(), expected_receivable_2.clone()],
- new_start_block: 123456789,
+ new_start_block: 123456789u64,
response_skeleton_opt: None,
})
.expect("unexpected actix error");
@@ -2019,7 +2142,8 @@ mod tests {
response_skeleton_opt: None,
}))
.stop_the_system_after_last_msg();
- let mut config = make_bc_with_defaults();
+ let earning_wallet = make_wallet("earning");
+ let mut config = bc_from_earning_wallet(earning_wallet.clone());
config.scan_intervals_opt = Some(ScanIntervals {
payable_scan_interval: Duration::from_secs(100),
receivable_scan_interval: Duration::from_millis(99),
@@ -2048,13 +2172,38 @@ mod tests {
send_start_message!(subject_subs);
+ let time_before = SystemTime::now();
system.run();
- let begin_scan_params = begin_scan_params_arc.lock().unwrap();
+ let time_after = SystemTime::now();
let notify_later_receivable_params = notify_later_receivable_params_arc.lock().unwrap();
TestLogHandler::new().exists_log_containing(&format!(
"DEBUG: {test_name}: There was nothing to process during Receivables scan."
));
- assert_eq!(begin_scan_params.len(), 2);
+ let mut begin_scan_params = begin_scan_params_arc.lock().unwrap();
+ let (
+ first_attempt_wallet,
+ first_attempt_timestamp,
+ first_attempt_response_skeleton_opt,
+ first_attempt_logger,
+ ) = begin_scan_params.remove(0);
+ let (
+ second_attempt_wallet,
+ second_attempt_timestamp,
+ second_attempt_response_skeleton_opt,
+ second_attempt_logger,
+ ) = begin_scan_params.remove(0);
+ assert_eq!(first_attempt_wallet, second_attempt_wallet);
+ assert_eq!(second_attempt_wallet, earning_wallet);
+ assert!(time_before <= first_attempt_timestamp);
+ assert!(first_attempt_timestamp <= second_attempt_timestamp);
+ assert!(second_attempt_timestamp <= time_after);
+ assert_eq!(first_attempt_response_skeleton_opt, None);
+ assert_eq!(second_attempt_response_skeleton_opt, None);
+ debug!(first_attempt_logger, "first attempt");
+ debug!(second_attempt_logger, "second attempt");
+ let tlh = TestLogHandler::new();
+ tlh.exists_log_containing(&format!("DEBUG: {test_name}: first attempt"));
+ tlh.exists_log_containing(&format!("DEBUG: {test_name}: second attempt"));
assert_eq!(
*notify_later_receivable_params,
vec![
@@ -2082,6 +2231,7 @@ mod tests {
let notify_later_pending_payable_params_arc = Arc::new(Mutex::new(vec![]));
let system = System::new(test_name);
SystemKillerActor::new(Duration::from_secs(10)).start(); // a safety net for GitHub Actions
+ let consuming_wallet = make_paying_wallet(b"consuming");
let pending_payable_scanner = ScannerMock::new()
.begin_scan_params(&begin_scan_params_arc)
.begin_scan_result(Err(BeginScanError::NothingToProcess))
@@ -2097,6 +2247,7 @@ mod tests {
pending_payable_scan_interval: Duration::from_millis(98),
});
let mut subject = AccountantBuilder::default()
+ .consuming_wallet(consuming_wallet.clone())
.bootstrapper_config(config)
.logger(Logger::new(test_name))
.build();
@@ -2119,14 +2270,39 @@ mod tests {
send_start_message!(subject_subs);
+ let time_before = SystemTime::now();
system.run();
- let begin_scan_params = begin_scan_params_arc.lock().unwrap();
+ let time_after = SystemTime::now();
let notify_later_pending_payable_params =
notify_later_pending_payable_params_arc.lock().unwrap();
TestLogHandler::new().exists_log_containing(&format!(
"DEBUG: {test_name}: There was nothing to process during PendingPayables scan."
));
- assert_eq!(begin_scan_params.len(), 2);
+ let mut begin_scan_params = begin_scan_params_arc.lock().unwrap();
+ let (
+ first_attempt_wallet,
+ first_attempt_timestamp,
+ first_attempt_response_skeleton_opt,
+ first_attempt_logger,
+ ) = begin_scan_params.remove(0);
+ let (
+ second_attempt_wallet,
+ second_attempt_timestamp,
+ second_attempt_response_skeleton_opt,
+ second_attempt_logger,
+ ) = begin_scan_params.remove(0);
+ assert_eq!(first_attempt_wallet, second_attempt_wallet);
+ assert_eq!(second_attempt_wallet, consuming_wallet);
+ assert!(time_before <= first_attempt_timestamp);
+ assert!(first_attempt_timestamp <= second_attempt_timestamp);
+ assert!(second_attempt_timestamp <= time_after);
+ assert_eq!(first_attempt_response_skeleton_opt, None);
+ assert_eq!(second_attempt_response_skeleton_opt, None);
+ debug!(first_attempt_logger, "first attempt");
+ debug!(second_attempt_logger, "second attempt");
+ let tlh = TestLogHandler::new();
+ tlh.exists_log_containing(&format!("DEBUG: {test_name}: first attempt"));
+ tlh.exists_log_containing(&format!("DEBUG: {test_name}: second attempt"));
assert_eq!(
*notify_later_pending_payable_params,
vec![
@@ -2154,6 +2330,7 @@ mod tests {
let notify_later_payables_params_arc = Arc::new(Mutex::new(vec![]));
let system = System::new(test_name);
SystemKillerActor::new(Duration::from_secs(10)).start(); // a safety net for GitHub Actions
+ let consuming_wallet = make_paying_wallet(b"consuming");
let payable_scanner = ScannerMock::new()
.begin_scan_params(&begin_scan_params_arc)
.begin_scan_result(Err(BeginScanError::NothingToProcess))
@@ -2161,6 +2338,7 @@ mod tests {
protected_qualified_payables: protect_payables_in_test(vec![make_payable_account(
123,
)]),
+ consuming_wallet: consuming_wallet.clone(),
response_skeleton_opt: None,
}))
.stop_the_system_after_last_msg();
@@ -2172,6 +2350,7 @@ mod tests {
});
let mut subject = AccountantBuilder::default()
.bootstrapper_config(config)
+ .consuming_wallet(consuming_wallet.clone())
.logger(Logger::new(test_name))
.build();
subject.scanners.payable = Box::new(payable_scanner);
@@ -2193,14 +2372,39 @@ mod tests {
send_start_message!(subject_subs);
+ let time_before = SystemTime::now();
system.run();
+ let time_after = SystemTime::now();
//the second attempt is the one where the queue is empty and System::current.stop() ends the cycle
- let begin_scan_params = begin_scan_params_arc.lock().unwrap();
let notify_later_payables_params = notify_later_payables_params_arc.lock().unwrap();
TestLogHandler::new().exists_log_containing(&format!(
"DEBUG: {test_name}: There was nothing to process during Payables scan."
));
- assert_eq!(begin_scan_params.len(), 2);
+ let mut begin_scan_params = begin_scan_params_arc.lock().unwrap();
+ let (
+ first_attempt_wallet,
+ first_attempt_timestamp,
+ first_attempt_response_skeleton_opt,
+ first_attempt_logger,
+ ) = begin_scan_params.remove(0);
+ let (
+ second_attempt_wallet,
+ second_attempt_timestamp,
+ second_attempt_response_skeleton_opt,
+ second_attempt_logger,
+ ) = begin_scan_params.remove(0);
+ assert_eq!(first_attempt_wallet, second_attempt_wallet);
+ assert_eq!(second_attempt_wallet, consuming_wallet);
+ assert!(time_before <= first_attempt_timestamp);
+ assert!(first_attempt_timestamp <= second_attempt_timestamp);
+ assert!(second_attempt_timestamp <= time_after);
+ assert_eq!(first_attempt_response_skeleton_opt, None);
+ assert_eq!(second_attempt_response_skeleton_opt, None);
+ debug!(first_attempt_logger, "first attempt");
+ debug!(second_attempt_logger, "second attempt");
+ let tlh = TestLogHandler::new();
+ tlh.exists_log_containing(&format!("DEBUG: {test_name}: first attempt"));
+ tlh.exists_log_containing(&format!("DEBUG: {test_name}: second attempt"));
assert_eq!(
*notify_later_payables_params,
vec![
@@ -2220,6 +2424,40 @@ mod tests {
)
}
+ #[test]
+ fn payable_scan_is_not_initiated_if_consuming_wallet_is_not_found() {
+ init_test_logging();
+ let test_name = "payable_scan_is_not_initiated_if_consuming_wallet_is_not_found";
+ let mut subject = AccountantBuilder::default().build();
+ subject.consuming_wallet_opt = None;
+ subject.logger = Logger::new(test_name);
+
+ subject.handle_request_of_scan_for_payable(None);
+
+ let has_scan_started = subject.scanners.payable.scan_started_at().is_some();
+ assert_eq!(has_scan_started, false);
+ TestLogHandler::new().exists_log_containing(&format!(
+ "DEBUG: {test_name}: Cannot initiate Payables scan because no consuming wallet was found."
+ ));
+ }
+
+ #[test]
+ fn pending_payable_scan_is_not_initiated_if_consuming_wallet_is_not_found() {
+ init_test_logging();
+ let test_name = "pending_payable_scan_is_not_initiated_if_consuming_wallet_is_not_found";
+ let mut subject = AccountantBuilder::default().build();
+ subject.consuming_wallet_opt = None;
+ subject.logger = Logger::new(test_name);
+
+ subject.handle_request_of_scan_for_pending_payable(None);
+
+ let has_scan_started = subject.scanners.pending_payable.scan_started_at().is_some();
+ assert_eq!(has_scan_started, false);
+ TestLogHandler::new().exists_log_containing(&format!(
+ "DEBUG: {test_name}: Cannot initiate PendingPayables scan because no consuming wallet was found."
+ ));
+ }
+
#[test]
fn start_message_triggers_no_scans_in_suppress_mode() {
init_test_logging();
@@ -2254,6 +2492,7 @@ mod tests {
#[test]
fn scan_for_payables_message_does_not_trigger_payment_for_balances_below_the_curve() {
init_test_logging();
+ let consuming_wallet = make_paying_wallet(b"consuming wallet");
let payment_thresholds = PaymentThresholds {
threshold_interval_sec: 2_592_000,
debt_threshold_gwei: 1_000_000_000,
@@ -2315,10 +2554,12 @@ mod tests {
.build();
subject.outbound_payments_instructions_sub_opt = Some(outbound_payments_instructions_sub);
- let _result = subject
- .scanners
- .payable
- .begin_scan(SystemTime::now(), None, &subject.logger);
+ let _result = subject.scanners.payable.begin_scan(
+ consuming_wallet,
+ SystemTime::now(),
+ None,
+ &subject.logger,
+ );
System::current().stop();
system.run();
@@ -2330,6 +2571,7 @@ mod tests {
fn scan_for_payable_message_triggers_payment_for_balances_over_the_curve() {
init_test_logging();
let mut config = bc_from_earning_wallet(make_wallet("mine"));
+ let consuming_wallet = make_paying_wallet(b"consuming");
config.scan_intervals_opt = Some(ScanIntervals {
pending_payable_scan_interval: Duration::from_secs(50_000),
payable_scan_interval: Duration::from_secs(50_000),
@@ -2376,6 +2618,7 @@ mod tests {
.build();
let mut subject = AccountantBuilder::default()
.bootstrapper_config(config)
+ .consuming_wallet(consuming_wallet.clone())
.payable_daos(vec![ForPayableScanner(payable_dao)])
.build();
subject.scanners.pending_payable = Box::new(NullScanner::new());
@@ -2393,6 +2636,7 @@ mod tests {
message,
&QualifiedPayablesMessage {
protected_qualified_payables: protect_payables_in_test(qualified_payables),
+ consuming_wallet,
response_skeleton_opt: None,
}
);
@@ -2426,6 +2670,7 @@ mod tests {
let config = bc_from_earning_wallet(make_wallet("mine"));
let system = System::new(test_name);
let mut subject = AccountantBuilder::default()
+ .consuming_wallet(make_paying_wallet(b"consuming"))
.logger(Logger::new(test_name))
.payable_daos(vec![ForPayableScanner(payable_dao)])
.bootstrapper_config(config)
@@ -2515,6 +2760,7 @@ mod tests {
let config = bc_from_earning_wallet(make_wallet("mine"));
let system = System::new("pending payable scan");
let mut subject = AccountantBuilder::default()
+ .consuming_wallet(make_paying_wallet(b"consuming"))
.pending_payable_daos(vec![ForPendingPayableScanner(pending_payable_dao)])
.bootstrapper_config(config)
.build();
@@ -3247,7 +3493,6 @@ mod tests {
Box::new(blockchain_interface),
Box::new(persistent_config),
false,
- Some(consuming_wallet.clone()),
);
let account_1 = PayableAccount {
wallet: wallet_account_1.clone(),
@@ -3355,10 +3600,12 @@ mod tests {
.delete_fingerprints_result(Ok(()));
pending_payable_dao_for_pending_payable_scanner
.have_return_all_errorless_fingerprints_shut_down_the_system = true;
+ let consuming_wallet_for_accountant = consuming_wallet.clone();
let accountant_addr = Arbiter::builder()
.stop_system_on_panic(true)
.start(move |_| {
let mut subject = AccountantBuilder::default()
+ .consuming_wallet(consuming_wallet_for_accountant)
.bootstrapper_config(bootstrapper_config)
.payable_daos(vec![
ForPayableScanner(payable_dao_for_payable_scanner),
@@ -4535,6 +4782,7 @@ mod tests {
let factory = Accountant::dao_factory(data_dir);
factory.make();
};
+
assert_on_initialization_with_panic_on_migration(&data_dir, &act);
}
}
diff --git a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/msgs.rs b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/msgs.rs
index d4cd40be4..41a1b3940 100644
--- a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/msgs.rs
+++ b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/msgs.rs
@@ -2,6 +2,7 @@
use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::blockchain_agent::BlockchainAgent;
use crate::accountant::{ResponseSkeleton, SkeletonOptHolder};
+use crate::sub_lib::wallet::Wallet;
use actix::Message;
use masq_lib::type_obfuscation::Obfuscated;
use std::fmt::Debug;
@@ -9,16 +10,19 @@ use std::fmt::Debug;
#[derive(Debug, Message, PartialEq, Eq, Clone)]
pub struct QualifiedPayablesMessage {
pub protected_qualified_payables: Obfuscated,
+ pub consuming_wallet: Wallet,
pub response_skeleton_opt: Option,
}
impl QualifiedPayablesMessage {
pub(in crate::accountant) fn new(
protected_qualified_payables: Obfuscated,
+ consuming_wallet: Wallet,
response_skeleton_opt: Option,
) -> Self {
Self {
protected_qualified_payables,
+ consuming_wallet,
response_skeleton_opt,
}
}
diff --git a/node/src/accountant/scanners/mod.rs b/node/src/accountant/scanners/mod.rs
index f1341ed10..fc5f5ce91 100644
--- a/node/src/accountant/scanners/mod.rs
+++ b/node/src/accountant/scanners/mod.rs
@@ -68,7 +68,6 @@ impl Scanners {
pub fn new(
dao_factories: DaoFactories,
payment_thresholds: Rc,
- earning_wallet: Rc,
when_pending_too_long_sec: u64,
financial_statistics: Rc>,
) -> Self {
@@ -94,7 +93,6 @@ impl Scanners {
dao_factories.banned_dao_factory.make(),
Box::new(persistent_configuration),
Rc::clone(&payment_thresholds),
- earning_wallet,
financial_statistics,
));
@@ -113,6 +111,7 @@ where
{
fn begin_scan(
&mut self,
+ wallet: Wallet,
timestamp: SystemTime,
response_skeleton_opt: Option,
logger: &Logger,
@@ -193,6 +192,7 @@ pub struct PayableScanner {
impl Scanner for PayableScanner {
fn begin_scan(
&mut self,
+ consuming_wallet: Wallet,
timestamp: SystemTime,
response_skeleton_opt: Option,
logger: &Logger,
@@ -225,8 +225,11 @@ impl Scanner for PayableScanner {
qualified_payables.len()
);
let protected_payables = self.protect_payables(qualified_payables);
- let outgoing_msg =
- QualifiedPayablesMessage::new(protected_payables, response_skeleton_opt);
+ let outgoing_msg = QualifiedPayablesMessage::new(
+ protected_payables,
+ consuming_wallet,
+ response_skeleton_opt,
+ );
Ok(outgoing_msg)
}
}
@@ -567,6 +570,7 @@ pub struct PendingPayableScanner {
impl Scanner for PendingPayableScanner {
fn begin_scan(
&mut self,
+ _irrelevant_wallet: Wallet,
timestamp: SystemTime,
response_skeleton_opt: Option,
logger: &Logger,
@@ -825,13 +829,13 @@ pub struct ReceivableScanner {
pub receivable_dao: Box,
pub banned_dao: Box,
pub persistent_configuration: Box,
- pub earning_wallet: Rc,
pub financial_statistics: Rc>,
}
impl Scanner for ReceivableScanner {
fn begin_scan(
&mut self,
+ earning_wallet: Wallet,
timestamp: SystemTime,
response_skeleton_opt: Option,
logger: &Logger,
@@ -840,14 +844,11 @@ impl Scanner for ReceivableScanner {
return Err(BeginScanError::ScanAlreadyRunning(timestamp));
}
self.mark_as_started(timestamp);
- info!(
- logger,
- "Scanning for receivables to {}", self.earning_wallet
- );
+ info!(logger, "Scanning for receivables to {}", earning_wallet);
self.scan_for_delinquencies(timestamp, logger);
Ok(RetrieveTransactions {
- recipient: self.earning_wallet.as_ref().clone(),
+ recipient: earning_wallet,
response_skeleton_opt,
})
}
@@ -861,7 +862,7 @@ impl Scanner for ReceivableScanner {
match self
.persistent_configuration
- .set_start_block(msg.new_start_block)
+ .set_start_block(Some(msg.new_start_block))
{
Ok(()) => debug!(logger, "Start block updated to {}", msg.new_start_block),
Err(e) => panic!(
@@ -893,12 +894,10 @@ impl ReceivableScanner {
banned_dao: Box,
persistent_configuration: Box,
payment_thresholds: Rc,
- earning_wallet: Rc,
financial_statistics: Rc>,
) -> Self {
Self {
common: ScannerCommon::new(payment_thresholds),
- earning_wallet,
receivable_dao,
banned_dao,
persistent_configuration,
@@ -915,7 +914,7 @@ impl ReceivableScanner {
let new_start_block = msg.new_start_block;
match self
.persistent_configuration
- .set_start_block_from_txn(new_start_block, &mut txn)
+ .set_start_block_from_txn(Some(new_start_block), &mut txn)
{
Ok(()) => (),
Err(e) => panic!(
@@ -985,6 +984,7 @@ impl ReceivableScanner {
#[derive(Debug, PartialEq, Eq)]
pub enum BeginScanError {
NothingToProcess,
+ NoConsumingWalletFound,
ScanAlreadyRunning(SystemTime),
CalledFromNullScanner, // Exclusive for tests
}
@@ -1007,6 +1007,10 @@ impl BeginScanError {
scan_type,
BeginScanError::timestamp_as_string(timestamp)
)),
+ BeginScanError::NoConsumingWalletFound => Some(format!(
+ "Cannot initiate {:?} scan because no consuming wallet was found.",
+ scan_type
+ )),
BeginScanError::CalledFromNullScanner => match cfg!(test) {
true => None,
false => panic!("Null Scanner shouldn't be running inside production code."),
@@ -1134,9 +1138,9 @@ mod tests {
DaoFactories, FinancialStatistics, PaymentThresholds, ScanIntervals,
DEFAULT_PAYMENT_THRESHOLDS,
};
- use crate::test_utils::make_wallet;
use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock;
use crate::test_utils::unshared_test_utils::arbitrary_id_stamp::ArbitraryIdStamp;
+ use crate::test_utils::{make_paying_wallet, make_wallet};
use actix::{Message, System};
use ethereum_types::U64;
use masq_lib::logger::Logger;
@@ -1175,7 +1179,6 @@ mod tests {
total_paid_payable_wei: 1,
total_paid_receivable_wei: 2,
};
- let earning_wallet = make_wallet("unique_wallet");
let payment_thresholds = make_custom_payment_thresholds();
let payment_thresholds_rc = Rc::new(payment_thresholds);
let initial_rc_count = Rc::strong_count(&payment_thresholds_rc);
@@ -1189,7 +1192,6 @@ mod tests {
config_dao_factory: Box::new(config_dao_factory),
},
Rc::clone(&payment_thresholds_rc),
- Rc::new(earning_wallet.clone()),
when_pending_too_long_sec,
Rc::new(RefCell::new(financial_statistics.clone())),
);
@@ -1234,10 +1236,6 @@ mod tests {
*receivable_scanner.financial_statistics.borrow(),
financial_statistics
);
- assert_eq!(
- receivable_scanner.earning_wallet.address(),
- earning_wallet.address()
- );
assert_eq!(
receivable_scanner.common.payment_thresholds.as_ref(),
&payment_thresholds
@@ -1245,7 +1243,7 @@ mod tests {
assert_eq!(receivable_scanner.common.initiated_at_opt.is_some(), false);
receivable_scanner
.persistent_configuration
- .set_start_block(136890)
+ .set_start_block(Some(136890))
.unwrap();
let set_params = set_params_arc.lock().unwrap();
assert_eq!(
@@ -1274,6 +1272,7 @@ mod tests {
fn payable_scanner_can_initiate_a_scan() {
init_test_logging();
let test_name = "payable_scanner_can_initiate_a_scan";
+ let consuming_wallet = make_paying_wallet(b"consuming wallet");
let now = SystemTime::now();
let (qualified_payable_accounts, _, all_non_pending_payables) =
make_payables(now, &PaymentThresholds::default());
@@ -1283,7 +1282,8 @@ mod tests {
.payable_dao(payable_dao)
.build();
- let result = subject.begin_scan(now, None, &Logger::new(test_name));
+ let result =
+ subject.begin_scan(consuming_wallet.clone(), now, None, &Logger::new(test_name));
let timestamp = subject.scan_started_at();
assert_eq!(timestamp, Some(now));
@@ -1293,6 +1293,7 @@ mod tests {
protected_qualified_payables: protect_payables_in_test(
qualified_payable_accounts.clone()
),
+ consuming_wallet,
response_skeleton_opt: None,
})
);
@@ -1307,6 +1308,7 @@ mod tests {
#[test]
fn payable_scanner_throws_error_when_a_scan_is_already_running() {
+ let consuming_wallet = make_paying_wallet(b"consuming wallet");
let now = SystemTime::now();
let (_, _, all_non_pending_payables) = make_payables(now, &PaymentThresholds::default());
let payable_dao =
@@ -1314,9 +1316,14 @@ mod tests {
let mut subject = PayableScannerBuilder::new()
.payable_dao(payable_dao)
.build();
- let _result = subject.begin_scan(now, None, &Logger::new("test"));
+ let _result = subject.begin_scan(consuming_wallet.clone(), now, None, &Logger::new("test"));
- let run_again_result = subject.begin_scan(SystemTime::now(), None, &Logger::new("test"));
+ let run_again_result = subject.begin_scan(
+ consuming_wallet,
+ SystemTime::now(),
+ None,
+ &Logger::new("test"),
+ );
let is_scan_running = subject.scan_started_at().is_some();
assert_eq!(is_scan_running, true);
@@ -1328,6 +1335,7 @@ mod tests {
#[test]
fn payable_scanner_throws_error_in_case_no_qualified_payable_is_found() {
+ let consuming_wallet = make_paying_wallet(b"consuming wallet");
let now = SystemTime::now();
let (_, unqualified_payable_accounts, _) =
make_payables(now, &PaymentThresholds::default());
@@ -1337,7 +1345,7 @@ mod tests {
.payable_dao(payable_dao)
.build();
- let result = subject.begin_scan(now, None, &Logger::new("test"));
+ let result = subject.begin_scan(consuming_wallet, now, None, &Logger::new("test"));
let is_scan_running = subject.scan_started_at().is_some();
assert_eq!(is_scan_running, false);
@@ -1623,7 +1631,7 @@ mod tests {
.iter()
.map(|ppayable| ppayable.hash)
.collect::>();
- // Not in an ascending order
+ // Not in ascending order
let rowids_and_hashes_from_fingerprints = vec![(hash_1, 3), (hash_3, 5), (hash_2, 6)]
.iter()
.map(|(hash, _id)| *hash)
@@ -1875,7 +1883,7 @@ mod tests {
00000000000000000000000000000000000000000315 failed due to RecordDeletion(\"Gosh, I overslept \
without an alarm set\")");
let log_handler = TestLogHandler::new();
- // There is a possible situation when we stumble over missing fingerprints and so we log it.
+ // There is a possible situation when we stumble over missing fingerprints, so we log it.
// Here we don't and so any ERROR log shouldn't turn up
log_handler.exists_no_log_containing(&format!("ERROR: {}", test_name))
}
@@ -2210,6 +2218,7 @@ mod tests {
fn pending_payable_scanner_can_initiate_a_scan() {
init_test_logging();
let test_name = "pending_payable_scanner_can_initiate_a_scan";
+ let consuming_wallet = make_paying_wallet(b"consuming wallet");
let now = SystemTime::now();
let payable_fingerprint_1 = PendingPayableFingerprint {
rowid: 555,
@@ -2234,7 +2243,12 @@ mod tests {
.pending_payable_dao(pending_payable_dao)
.build();
- let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name));
+ let result = pending_payable_scanner.begin_scan(
+ consuming_wallet,
+ now,
+ None,
+ &Logger::new(test_name),
+ );
let no_of_pending_payables = fingerprints.len();
let is_scan_running = pending_payable_scanner.scan_started_at().is_some();
@@ -2257,6 +2271,7 @@ mod tests {
#[test]
fn pending_payable_scanner_throws_error_in_case_scan_is_already_running() {
let now = SystemTime::now();
+ let consuming_wallet = make_paying_wallet(b"consuming");
let pending_payable_dao = PendingPayableDaoMock::new()
.return_all_errorless_fingerprints_result(vec![PendingPayableFingerprint {
rowid: 1234,
@@ -2270,9 +2285,9 @@ mod tests {
.pending_payable_dao(pending_payable_dao)
.build();
let logger = Logger::new("test");
- let _ = subject.begin_scan(now, None, &logger);
+ let _ = subject.begin_scan(consuming_wallet.clone(), now, None, &logger);
- let result = subject.begin_scan(SystemTime::now(), None, &logger);
+ let result = subject.begin_scan(consuming_wallet, SystemTime::now(), None, &logger);
let is_scan_running = subject.scan_started_at().is_some();
assert_eq!(is_scan_running, true);
@@ -2282,13 +2297,15 @@ mod tests {
#[test]
fn pending_payable_scanner_throws_an_error_when_no_fingerprint_is_found() {
let now = SystemTime::now();
+ let consuming_wallet = make_paying_wallet(b"consuming_wallet");
let pending_payable_dao =
PendingPayableDaoMock::new().return_all_errorless_fingerprints_result(vec![]);
let mut pending_payable_scanner = PendingPayableScannerBuilder::new()
.pending_payable_dao(pending_payable_dao)
.build();
- let result = pending_payable_scanner.begin_scan(now, None, &Logger::new("test"));
+ let result =
+ pending_payable_scanner.begin_scan(consuming_wallet, now, None, &Logger::new("test"));
let is_scan_running = pending_payable_scanner.scan_started_at().is_some();
assert_eq!(result, Err(BeginScanError::NothingToProcess));
@@ -2924,10 +2941,14 @@ mod tests {
let earning_wallet = make_wallet("earning");
let mut receivable_scanner = ReceivableScannerBuilder::new()
.receivable_dao(receivable_dao)
- .earning_wallet(earning_wallet.clone())
.build();
- let result = receivable_scanner.begin_scan(now, None, &Logger::new(test_name));
+ let result = receivable_scanner.begin_scan(
+ earning_wallet.clone(),
+ now,
+ None,
+ &Logger::new(test_name),
+ );
let is_scan_running = receivable_scanner.scan_started_at().is_some();
assert_eq!(is_scan_running, true);
@@ -2952,11 +2973,16 @@ mod tests {
let earning_wallet = make_wallet("earning");
let mut receivable_scanner = ReceivableScannerBuilder::new()
.receivable_dao(receivable_dao)
- .earning_wallet(earning_wallet)
.build();
- let _ = receivable_scanner.begin_scan(now, None, &Logger::new("test"));
+ let _ =
+ receivable_scanner.begin_scan(earning_wallet.clone(), now, None, &Logger::new("test"));
- let result = receivable_scanner.begin_scan(SystemTime::now(), None, &Logger::new("test"));
+ let result = receivable_scanner.begin_scan(
+ earning_wallet,
+ SystemTime::now(),
+ None,
+ &Logger::new("test"),
+ );
let is_scan_running = receivable_scanner.scan_started_at().is_some();
assert_eq!(is_scan_running, true);
@@ -2989,12 +3015,11 @@ mod tests {
.receivable_dao(receivable_dao)
.banned_dao(banned_dao)
.payment_thresholds(payment_thresholds)
- .earning_wallet(earning_wallet.clone())
.build();
let logger = Logger::new("DELINQUENCY_TEST");
let now = SystemTime::now();
- let result = receivable_scanner.begin_scan(now, None, &logger);
+ let result = receivable_scanner.begin_scan(earning_wallet.clone(), now, None, &logger);
assert_eq!(
result,
@@ -3045,6 +3070,7 @@ mod tests {
let set_start_block_params_arc = Arc::new(Mutex::new(vec![]));
let new_start_block = 4321;
let persistent_config = PersistentConfigurationMock::new()
+ .start_block_result(Ok(None))
.set_start_block_params(&set_start_block_params_arc)
.set_start_block_result(Ok(()));
let mut subject = ReceivableScannerBuilder::new()
@@ -3061,7 +3087,7 @@ mod tests {
assert_eq!(message_opt, None);
let set_start_block_params = set_start_block_params_arc.lock().unwrap();
- assert_eq!(*set_start_block_params, vec![4321]);
+ assert_eq!(*set_start_block_params, vec![Some(4321)]);
TestLogHandler::new().exists_log_containing(&format!(
"INFO: {test_name}: No newly received payments were detected during the scanning process."
));
@@ -3074,16 +3100,21 @@ mod tests {
init_test_logging();
let test_name = "no_transactions_received_but_start_block_setting_fails";
let now = SystemTime::now();
- let persistent_config = PersistentConfigurationMock::new().set_start_block_result(Err(
- PersistentConfigError::UninterpretableValue("Illiterate database manager".to_string()),
- ));
+ let set_start_block_params_arc = Arc::new(Mutex::new(vec![]));
+ let new_start_block = 6709u64;
+ let persistent_config = PersistentConfigurationMock::new()
+ .start_block_result(Ok(None))
+ .set_start_block_params(&set_start_block_params_arc)
+ .set_start_block_result(Err(PersistentConfigError::UninterpretableValue(
+ "Illiterate database manager".to_string(),
+ )));
let mut subject = ReceivableScannerBuilder::new()
.persistent_configuration(persistent_config)
.build();
let msg = ReceivedPayments {
timestamp: now,
payments: vec![],
- new_start_block: 6709,
+ new_start_block,
response_skeleton_opt: None,
};
// Not necessary, rather for preciseness
@@ -3107,6 +3138,7 @@ mod tests {
.set_arbitrary_id_stamp(transaction_id);
let transaction = TransactionSafeWrapper::new_with_builder(txn_inner_builder);
let persistent_config = PersistentConfigurationMock::new()
+ .start_block_result(Ok(None))
.set_start_block_from_txn_params(&set_start_block_from_txn_params_arc)
.set_start_block_from_txn_result(Ok(()));
let receivable_dao = ReceivableDaoMock::new()
@@ -3153,7 +3185,7 @@ mod tests {
let set_by_guest_transaction_params = set_start_block_from_txn_params_arc.lock().unwrap();
assert_eq!(
*set_by_guest_transaction_params,
- vec![(7890123, transaction_id)]
+ vec![(Some(7890123u64), transaction_id)]
);
let commit_params = commit_params_arc.lock().unwrap();
assert_eq!(*commit_params, vec![()]);
@@ -3171,9 +3203,11 @@ mod tests {
let now = SystemTime::now();
let txn_inner_builder = TransactionInnerWrapperMockBuilder::default();
let transaction = TransactionSafeWrapper::new_with_builder(txn_inner_builder);
- let persistent_config = PersistentConfigurationMock::new().set_start_block_from_txn_result(
- Err(PersistentConfigError::DatabaseError("Fatigue".to_string())),
- );
+ let persistent_config = PersistentConfigurationMock::new()
+ .start_block_result(Ok(None))
+ .set_start_block_from_txn_result(Err(PersistentConfigError::DatabaseError(
+ "Fatigue".to_string(),
+ )));
let receivable_dao = ReceivableDaoMock::new().more_money_received_result(transaction);
let mut subject = ReceivableScannerBuilder::new()
.receivable_dao(receivable_dao)
@@ -3215,8 +3249,9 @@ mod tests {
let txn_inner_builder =
TransactionInnerWrapperMockBuilder::default().commit_result(commit_err);
let transaction = TransactionSafeWrapper::new_with_builder(txn_inner_builder);
- let persistent_config =
- PersistentConfigurationMock::new().set_start_block_from_txn_result(Ok(()));
+ let persistent_config = PersistentConfigurationMock::new()
+ .start_block_result(Ok(None))
+ .set_start_block_from_txn_result(Ok(()));
let receivable_dao = ReceivableDaoMock::new().more_money_received_result(transaction);
let mut subject = ReceivableScannerBuilder::new()
.receivable_dao(receivable_dao)
diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs
index 38c7c56ec..6de6968ac 100644
--- a/node/src/accountant/test_utils.rs
+++ b/node/src/accountant/test_utils.rs
@@ -95,25 +95,27 @@ pub fn make_payable_account_with_wallet_and_balance_and_timestamp_opt(
}
pub struct AccountantBuilder {
- config: Option,
- logger: Option,
- payable_dao_factory: Option,
- receivable_dao_factory: Option,
- pending_payable_dao_factory: Option,
- banned_dao_factory: Option,
- config_dao_factory: Option,
+ config_opt: Option,
+ consuming_wallet_opt: Option,
+ logger_opt: Option,
+ payable_dao_factory_opt: Option,
+ receivable_dao_factory_opt: Option,
+ pending_payable_dao_factory_opt: Option,
+ banned_dao_factory_opt: Option,
+ config_dao_factory_opt: Option,
}
impl Default for AccountantBuilder {
fn default() -> Self {
Self {
- config: None,
- logger: None,
- payable_dao_factory: None,
- receivable_dao_factory: None,
- pending_payable_dao_factory: None,
- banned_dao_factory: None,
- config_dao_factory: None,
+ config_opt: None,
+ consuming_wallet_opt: None,
+ logger_opt: None,
+ payable_dao_factory_opt: None,
+ receivable_dao_factory_opt: None,
+ pending_payable_dao_factory_opt: None,
+ banned_dao_factory_opt: None,
+ config_dao_factory_opt: None,
}
}
}
@@ -262,12 +264,17 @@ const RECEIVABLE_DAOS_ACCOUNTANT_INITIALIZATION_ORDER: [DestinationMarker; 2] =
impl AccountantBuilder {
pub fn bootstrapper_config(mut self, config: BootstrapperConfig) -> Self {
- self.config = Some(config);
+ self.config_opt = Some(config);
+ self
+ }
+
+ pub fn consuming_wallet(mut self, consuming_wallet: Wallet) -> Self {
+ self.consuming_wallet_opt = Some(consuming_wallet);
self
}
pub fn logger(mut self, logger: Logger) -> Self {
- self.logger = Some(logger);
+ self.logger_opt = Some(logger);
self
}
@@ -278,7 +285,7 @@ impl AccountantBuilder {
create_or_update_factory!(
specially_configured_daos,
PENDING_PAYABLE_DAOS_ACCOUNTANT_INITIALIZATION_ORDER,
- pending_payable_dao_factory,
+ pending_payable_dao_factory_opt,
PendingPayableDaoFactoryMock,
PendingPayableDao,
self
@@ -292,7 +299,7 @@ impl AccountantBuilder {
create_or_update_factory!(
specially_configured_daos,
PAYABLE_DAOS_ACCOUNTANT_INITIALIZATION_ORDER,
- payable_dao_factory,
+ payable_dao_factory_opt,
PayableDaoFactoryMock,
PayableDao,
self
@@ -306,7 +313,7 @@ impl AccountantBuilder {
create_or_update_factory!(
specially_configured_daos,
RECEIVABLE_DAOS_ACCOUNTANT_INITIALIZATION_ORDER,
- receivable_dao_factory,
+ receivable_dao_factory_opt,
ReceivableDaoFactoryMock,
ReceivableDao,
self
@@ -315,46 +322,47 @@ impl AccountantBuilder {
//TODO this method seems to be never used?
pub fn banned_dao(mut self, banned_dao: BannedDaoMock) -> Self {
- match self.banned_dao_factory {
+ match self.banned_dao_factory_opt {
None => {
- self.banned_dao_factory = Some(BannedDaoFactoryMock::new().make_result(banned_dao))
+ self.banned_dao_factory_opt =
+ Some(BannedDaoFactoryMock::new().make_result(banned_dao))
}
Some(banned_dao_factory) => {
- self.banned_dao_factory = Some(banned_dao_factory.make_result(banned_dao))
+ self.banned_dao_factory_opt = Some(banned_dao_factory.make_result(banned_dao))
}
}
self
}
pub fn config_dao(mut self, config_dao: ConfigDaoMock) -> Self {
- self.config_dao_factory = Some(ConfigDaoFactoryMock::new().make_result(config_dao));
+ self.config_dao_factory_opt = Some(ConfigDaoFactoryMock::new().make_result(config_dao));
self
}
pub fn build(self) -> Accountant {
- let config = self.config.unwrap_or(make_bc_with_defaults());
- let payable_dao_factory = self.payable_dao_factory.unwrap_or(
+ let config = self.config_opt.unwrap_or(make_bc_with_defaults());
+ let payable_dao_factory = self.payable_dao_factory_opt.unwrap_or(
PayableDaoFactoryMock::new()
.make_result(PayableDaoMock::new())
.make_result(PayableDaoMock::new())
.make_result(PayableDaoMock::new()),
);
- let receivable_dao_factory = self.receivable_dao_factory.unwrap_or(
+ let receivable_dao_factory = self.receivable_dao_factory_opt.unwrap_or(
ReceivableDaoFactoryMock::new()
.make_result(ReceivableDaoMock::new())
.make_result(ReceivableDaoMock::new()),
);
- let pending_payable_dao_factory = self.pending_payable_dao_factory.unwrap_or(
+ let pending_payable_dao_factory = self.pending_payable_dao_factory_opt.unwrap_or(
PendingPayableDaoFactoryMock::new()
.make_result(PendingPayableDaoMock::new())
.make_result(PendingPayableDaoMock::new())
.make_result(PendingPayableDaoMock::new()),
);
let banned_dao_factory = self
- .banned_dao_factory
+ .banned_dao_factory_opt
.unwrap_or(BannedDaoFactoryMock::new().make_result(BannedDaoMock::new()));
let config_dao_factory = self
- .config_dao_factory
+ .config_dao_factory_opt
.unwrap_or(ConfigDaoFactoryMock::new().make_result(ConfigDaoMock::new()));
let mut accountant = Accountant::new(
config,
@@ -366,9 +374,12 @@ impl AccountantBuilder {
config_dao_factory: Box::new(config_dao_factory),
},
);
- if let Some(logger) = self.logger {
+ if let Some(logger) = self.logger_opt {
accountant.logger = logger;
}
+ if let Some(consuming_wallet) = self.consuming_wallet_opt {
+ accountant.consuming_wallet_opt = Some(consuming_wallet);
+ }
accountant
}
@@ -1176,7 +1187,6 @@ pub struct ReceivableScannerBuilder {
banned_dao: BannedDaoMock,
persistent_configuration: PersistentConfigurationMock,
payment_thresholds: PaymentThresholds,
- earning_wallet: Wallet,
financial_statistics: FinancialStatistics,
}
@@ -1187,7 +1197,6 @@ impl ReceivableScannerBuilder {
banned_dao: BannedDaoMock::new(),
persistent_configuration: PersistentConfigurationMock::new(),
payment_thresholds: PaymentThresholds::default(),
- earning_wallet: make_wallet("earning_default"),
financial_statistics: FinancialStatistics::default(),
}
}
@@ -1215,18 +1224,12 @@ impl ReceivableScannerBuilder {
self
}
- pub fn earning_wallet(mut self, earning_wallet: Wallet) -> Self {
- self.earning_wallet = earning_wallet;
- self
- }
-
pub fn build(self) -> ReceivableScanner {
ReceivableScanner::new(
Box::new(self.receivable_dao),
Box::new(self.banned_dao),
Box::new(self.persistent_configuration),
Rc::new(self.payment_thresholds),
- Rc::new(self.earning_wallet),
Rc::new(RefCell::new(self.financial_statistics)),
)
}
@@ -1538,6 +1541,7 @@ where
{
fn begin_scan(
&mut self,
+ _wallet_opt: Wallet,
_timestamp: SystemTime,
_response_skeleton_opt: Option,
_logger: &Logger,
@@ -1579,7 +1583,7 @@ impl NullScanner {
}
pub struct ScannerMock {
- begin_scan_params: Arc>>,
+ begin_scan_params: Arc, Logger)>>>,
begin_scan_results: RefCell>>,
end_scan_params: Arc>>,
end_scan_results: RefCell>>,
@@ -1594,11 +1598,17 @@ where
{
fn begin_scan(
&mut self,
- _timestamp: SystemTime,
- _response_skeleton_opt: Option,
- _logger: &Logger,
+ wallet: Wallet,
+ timestamp: SystemTime,
+ response_skeleton_opt: Option,
+ logger: &Logger,
) -> Result {
- self.begin_scan_params.lock().unwrap().push(());
+ self.begin_scan_params.lock().unwrap().push((
+ wallet,
+ timestamp,
+ response_skeleton_opt,
+ logger.clone(),
+ ));
if self.is_allowed_to_stop_the_system() && self.is_last_message() {
System::current().stop();
}
@@ -1643,7 +1653,10 @@ impl ScannerMock {
}
}
- pub fn begin_scan_params(mut self, params: &Arc>>) -> Self {
+ pub fn begin_scan_params(
+ mut self,
+ params: &Arc, Logger)>>>,
+ ) -> Self {
self.begin_scan_params = params.clone();
self
}
diff --git a/node/src/actor_system_factory.rs b/node/src/actor_system_factory.rs
index 0b175a797..2a03d024c 100644
--- a/node/src/actor_system_factory.rs
+++ b/node/src/actor_system_factory.rs
@@ -506,7 +506,6 @@ impl ActorFactory for ActorFactoryReal {
.blockchain_service_url_opt
.clone();
let crashable = is_crashable(config);
- let wallet_opt = config.consuming_wallet_opt.clone();
let data_directory = config.data_directory.clone();
let chain = config.blockchain_bridge_config.chain;
let arbiter = Arbiter::builder().stop_system_on_panic(true);
@@ -517,12 +516,7 @@ impl ActorFactory for ActorFactoryReal {
);
let persistent_config =
BlockchainBridge::initialize_persistent_configuration(&data_directory);
- BlockchainBridge::new(
- blockchain_interface,
- persistent_config,
- crashable,
- wallet_opt,
- )
+ BlockchainBridge::new(blockchain_interface, persistent_config, crashable)
});
subs_factory.make(&addr)
}
@@ -1179,7 +1173,6 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
},
payment_thresholds_opt: Some(PaymentThresholds::default()),
when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC,
@@ -1255,7 +1248,7 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
+
},
payment_thresholds_opt: Default::default(),
when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC
@@ -1401,7 +1394,6 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
let make_params_arc = Arc::new(Mutex::new(vec![]));
let mut subject = make_subject_with_null_setter();
@@ -1556,7 +1548,7 @@ mod tests {
neighborhood_config: NeighborhoodConfig {
mode: NeighborhoodMode::ConsumeOnly(vec![]),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
+
},
payment_thresholds_opt: Default::default(),
when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC
@@ -1746,7 +1738,6 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
},
node_descriptor: Default::default(),
payment_thresholds_opt: Default::default(),
diff --git a/node/src/apps.rs b/node/src/apps.rs
index 9aed6369b..2a38c7e47 100644
--- a/node/src/apps.rs
+++ b/node/src/apps.rs
@@ -6,7 +6,7 @@ use lazy_static::lazy_static;
use masq_lib::constants::{HIGHEST_USABLE_PORT, LOWEST_USABLE_INSECURE_PORT};
use masq_lib::shared_schema::{
chain_arg, data_directory_arg, db_password_arg, real_user_arg, shared_app, ui_port_arg,
- DB_PASSWORD_HELP,
+ DATA_DIRECTORY_HELP, DB_PASSWORD_HELP,
};
use masq_lib::utils::DATA_DIRECTORY_DAEMON_HELP;
@@ -36,7 +36,9 @@ pub fn app_daemon() -> App<'static, 'static> {
}
pub fn app_node() -> App<'static, 'static> {
- shared_app(app_head().after_help(NODE_HELP_TEXT)).arg(ui_port_arg(&DAEMON_UI_PORT_HELP))
+ shared_app(app_head().after_help(NODE_HELP_TEXT))
+ .arg(data_directory_arg(DATA_DIRECTORY_HELP))
+ .arg(ui_port_arg(&DAEMON_UI_PORT_HELP))
}
pub fn app_config_dumper() -> App<'static, 'static> {
@@ -107,9 +109,9 @@ mod tests {
let polygon_mainnet_dir = Path::new(&data_dir.to_str().unwrap())
.join("MASQ")
.join("polygon-mainnet");
- let polygon_mumbai_dir = Path::new(&data_dir.to_str().unwrap())
+ let polygon_amoy_dir = Path::new(&data_dir.to_str().unwrap())
.join("MASQ")
- .join("polygon-mumbai");
+ .join("polygon-amoy");
assert_eq!(
DATA_DIRECTORY_DAEMON_HELP.as_str(),
@@ -117,7 +119,7 @@ mod tests {
and by default its configuration file as well. By default, your data-directory is located in \
your application directory, under your home directory e.g.: '{}'.\n\n\
In case you change your chain to a different one, the data-directory path is automatically changed \
- to end with the name of your chain: e.g.: if you choose polygon-mumbai, then data-directory is \
+ to end with the name of your chain: e.g.: if you choose polygon-amoy, then data-directory is \
automatically changed to: '{}'.\n\n\
You can specify your own data-directory to the Daemon in two different ways: \n\n\
1. If you provide a path without the chain name on the end, the Daemon will automatically change \
@@ -126,7 +128,7 @@ mod tests {
2. If you provide your data directory with the corresponding chain name on the end, eg: {}/masq_home/polygon-mainnet, \
there will be no change until you set the chain parameter to a different value.",
polygon_mainnet_dir.to_string_lossy().to_string().as_str(),
- polygon_mumbai_dir.to_string_lossy().to_string().as_str(),
+ polygon_amoy_dir.to_string_lossy().to_string().as_str(),
&home_dir.to_string_lossy().to_string().as_str(),
&home_dir.to_string_lossy().to_string().as_str(),
home_dir.to_string_lossy().to_string().as_str()
diff --git a/node/src/blockchain/blockchain_bridge.rs b/node/src/blockchain/blockchain_bridge.rs
index 93e4d9bb1..67d018e27 100644
--- a/node/src/blockchain/blockchain_bridge.rs
+++ b/node/src/blockchain/blockchain_bridge.rs
@@ -33,6 +33,7 @@ use actix::Message;
use actix::{Addr, Recipient};
use itertools::Itertools;
use masq_lib::blockchains::chains::Chain;
+use masq_lib::constants::DEFAULT_MAX_BLOCK_COUNT;
use masq_lib::logger::Logger;
use masq_lib::messages::ScanType;
use masq_lib::ui_gateway::NodeFromUiMessage;
@@ -45,7 +46,6 @@ use web3::types::{BlockNumber, TransactionReceipt, H256};
pub const CRASH_KEY: &str = "BLOCKCHAINBRIDGE";
pub struct BlockchainBridge {
- consuming_wallet_opt: Option,
blockchain_interface: Box,
logger: Logger,
persistent_config: Box,
@@ -81,16 +81,8 @@ impl Handler for BlockchainBridge {
self.sent_payable_subs_opt = Some(msg.peer_actors.accountant.report_sent_payments);
self.received_payments_subs_opt = Some(msg.peer_actors.accountant.report_inbound_payments);
self.scan_error_subs_opt = Some(msg.peer_actors.accountant.scan_errors);
- match self.consuming_wallet_opt.as_ref() {
- Some(wallet) => debug!(
- self.logger,
- "Received BindMessage; consuming wallet address {}", wallet
- ),
- None => debug!(
- self.logger,
- "Received BindMessage; no consuming wallet address specified"
- ),
- }
+ // There's a multinode integration test looking for this message
+ debug!(self.logger, "Received BindMessage");
}
}
@@ -185,10 +177,8 @@ impl BlockchainBridge {
blockchain_interface: Box,
persistent_config: Box,
crashable: bool,
- consuming_wallet_opt: Option,
) -> BlockchainBridge {
BlockchainBridge {
- consuming_wallet_opt,
blockchain_interface,
persistent_config,
sent_payable_subs_opt: None,
@@ -244,18 +234,9 @@ impl BlockchainBridge {
&mut self,
incoming_message: QualifiedPayablesMessage,
) -> Result<(), String> {
- let consuming_wallet = if let Some(wallet) = self.consuming_wallet_opt.as_ref() {
- wallet
- } else {
- return Err(
- "Cannot inspect available balances for payables while consuming wallet is missing"
- .to_string(),
- );
- };
-
let agent = self
.blockchain_interface
- .build_blockchain_agent(consuming_wallet, &*self.persistent_config)
+ .build_blockchain_agent(&incoming_message.consuming_wallet, &*self.persistent_config)
.map_err(to_string)?;
let outgoing_message = BlockchainAgentWithContextMessage::new(
@@ -301,66 +282,99 @@ impl BlockchainBridge {
fn handle_retrieve_transactions(&mut self, msg: RetrieveTransactions) -> Result<(), String> {
let start_block_nbr = match self.persistent_config.start_block() {
- Ok (sb) => sb,
- Err (e) => panic! ("Cannot retrieve start block from database; payments to you may not be processed: {:?}", e)
+ Ok(Some(sb)) => sb,
+ Ok(None) => u64::MAX,
+ Err(e) => panic!("Cannot retrieve start block from database; payments to you may not be processed: {:?}", e)
};
let max_block_count = match self.persistent_config.max_block_count() {
Ok(Some(mbc)) => mbc,
- _ => u64::MAX,
+ _ => DEFAULT_MAX_BLOCK_COUNT,
};
+ let use_unlimited_block_count_range = u64::MAX == max_block_count;
+ let use_latest_block = u64::MAX == start_block_nbr;
let end_block = match self
.blockchain_interface
.lower_interface()
.get_block_number()
{
Ok(eb) => {
- if u64::MAX == max_block_count {
+ if use_unlimited_block_count_range || use_latest_block {
BlockNumber::Number(eb)
} else {
BlockNumber::Number(eb.as_u64().min(start_block_nbr + max_block_count).into())
}
}
Err(e) => {
- info!(
- self.logger,
- "Using 'latest' block number instead of a literal number. {:?}", e
- );
- if max_block_count == u64::MAX {
+ if use_unlimited_block_count_range || use_latest_block {
+ debug!(
+ self.logger,
+ "Using 'latest' block number instead of a literal number. {:?}", e
+ );
BlockNumber::Latest
} else {
+ debug!(
+ self.logger,
+ "Using '{}' ending block number. {:?}",
+ start_block_nbr + max_block_count,
+ e
+ );
BlockNumber::Number((start_block_nbr + max_block_count).into())
}
}
};
- let start_block = BlockNumber::Number(start_block_nbr.into());
+ let start_block = if use_latest_block {
+ end_block
+ } else {
+ BlockNumber::Number(start_block_nbr.into())
+ };
let retrieved_transactions =
self.blockchain_interface
.retrieve_transactions(start_block, end_block, &msg.recipient);
match retrieved_transactions {
Ok(transactions) => {
- if transactions.transactions.is_empty() {
- debug!(self.logger, "No new receivable detected");
+ if let BlockNumber::Number(new_start_block_number) = transactions.new_start_block {
+ if transactions.transactions.is_empty() {
+ debug!(self.logger, "No new receivable detected");
+ }
+ self.received_payments_subs_opt
+ .as_ref()
+ .expect("Accountant is unbound")
+ .try_send(ReceivedPayments {
+ timestamp: SystemTime::now(),
+ payments: transactions.transactions,
+ new_start_block: new_start_block_number.as_u64(),
+ response_skeleton_opt: msg.response_skeleton_opt,
+ })
+ .expect("Accountant is dead.");
}
- self.received_payments_subs_opt
- .as_ref()
- .expect("Accountant is unbound")
- .try_send(ReceivedPayments {
- timestamp: SystemTime::now(),
- payments: transactions.transactions,
- new_start_block: transactions.new_start_block,
- response_skeleton_opt: msg.response_skeleton_opt,
- })
- .expect("Accountant is dead.");
Ok(())
}
Err(e) => {
if let Some(max_block_count) = self.extract_max_block_count(e.clone()) {
- debug!(self.logger, "Writing max_block_count({})", max_block_count);
+ debug!(self.logger, "Writing max_block_count({})", &max_block_count);
self.persistent_config
.set_max_block_count(Some(max_block_count))
- .unwrap_or_else(|_| panic!("Writing max_block_count failed: {:?}", e));
+ .map_or_else(
+ |_| {
+ warning!(self.logger, "{} update max_block_count to {}. Scheduling next scan with that limit.", e, &max_block_count);
+ Err(format!("{} updated max_block_count to {}. Scheduling next scan with that limit.", e, &max_block_count))
+ },
+ |e| {
+ warning!(self.logger, "Writing max_block_count failed: {:?}", e);
+ Err(format!("Writing max_block_count failed: {:?}", e))
+ },
+ )
+ } else {
+ warning!(
+ self.logger,
+ "Attempted to retrieve received payments but failed: {:?}",
+ e
+ );
+ Err(format!(
+ "Attempted to retrieve received payments but failed: {:?}",
+ e
+ ))
}
- Err(format!("Could not retrieve Transactions: {:?}", e))
}
}
}
@@ -458,7 +472,7 @@ impl BlockchainBridge {
pub fn extract_max_block_count(&self, error: BlockchainError) -> Option {
let regex_result =
- Regex::new(r".* (max: |allowed for your plan: |is limited to |block range limit \()(?P\d+).*")
+ Regex::new(r".* (max: |allowed for your plan: |is limited to |block range limit \(|exceeds max block range )(?P\d+).*")
.expect("Invalid regex");
let max_block_count = match error {
BlockchainError::QueryFailed(msg) => match regex_result.captures(msg.as_str()) {
@@ -503,7 +517,6 @@ mod tests {
use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::test_utils::BlockchainAgentMock;
use crate::accountant::scanners::test_utils::protect_payables_in_test;
use crate::accountant::test_utils::make_pending_payable_fingerprint;
- use crate::blockchain::bip32::Bip32EncryptionKeyProvider;
use crate::blockchain::blockchain_interface::blockchain_interface_null::BlockchainInterfaceNull;
use crate::blockchain::blockchain_interface::data_structures::errors::{
BlockchainAgentBuildError, PayableTransactionError,
@@ -523,8 +536,8 @@ mod tests {
use crate::test_utils::recorder_stop_conditions::StopConditions;
use crate::test_utils::unshared_test_utils::arbitrary_id_stamp::ArbitraryIdStamp;
use crate::test_utils::unshared_test_utils::{
- assert_on_initialization_with_panic_on_migration, configure_default_persistent_config,
- prove_that_crash_request_handler_is_hooked_up, AssertionsMessage, ZERO,
+ assert_on_initialization_with_panic_on_migration,
+ prove_that_crash_request_handler_is_hooked_up, AssertionsMessage,
};
use crate::test_utils::{make_paying_wallet, make_wallet};
use actix::System;
@@ -534,7 +547,6 @@ mod tests {
use masq_lib::test_utils::logging::init_test_logging;
use masq_lib::test_utils::logging::TestLogHandler;
use masq_lib::test_utils::utils::{ensure_node_home_directory_exists, TEST_DEFAULT_CHAIN};
- use rustc_hex::FromHex;
use std::any::TypeId;
use std::path::Path;
use std::sync::{Arc, Mutex};
@@ -558,40 +570,6 @@ mod tests {
assert_eq!(CRASH_KEY, "BLOCKCHAINBRIDGE");
}
- fn stub_bi() -> Box {
- Box::new(BlockchainInterfaceMock::default())
- }
-
- #[test]
- fn blockchain_bridge_receives_bind_message_with_consuming_private_key() {
- init_test_logging();
- let secret: Vec = "cc46befe8d169b89db447bd725fc2368b12542113555302598430cb5d5c74ea9"
- .from_hex()
- .unwrap();
- let consuming_wallet =
- Wallet::from(Bip32EncryptionKeyProvider::from_raw_secret(&secret).unwrap());
- let subject = BlockchainBridge::new(
- stub_bi(),
- Box::new(configure_default_persistent_config(ZERO)),
- false,
- Some(consuming_wallet.clone()),
- );
- let system = System::new("blockchain_bridge_receives_bind_message");
- let addr = subject.start();
-
- addr.try_send(BindMessage {
- peer_actors: peer_actors_builder().build(),
- })
- .unwrap();
-
- System::current().stop();
- system.run();
- TestLogHandler::new().exists_log_containing(&format!(
- "DEBUG: BlockchainBridge: Received BindMessage; consuming wallet address {}",
- consuming_wallet
- ));
- }
-
#[test]
fn blockchain_interface_null_as_result_of_missing_blockchain_service_url() {
let result = BlockchainBridge::initialize_blockchain_interface(None, TEST_DEFAULT_CHAIN);
@@ -602,30 +580,6 @@ mod tests {
.unwrap();
}
- #[test]
- fn blockchain_bridge_receives_bind_message_without_consuming_private_key() {
- init_test_logging();
- let subject = BlockchainBridge::new(
- stub_bi(),
- Box::new(PersistentConfigurationMock::default()),
- false,
- None,
- );
- let system = System::new("blockchain_bridge_receives_bind_message");
- let addr = subject.start();
-
- addr.try_send(BindMessage {
- peer_actors: peer_actors_builder().build(),
- })
- .unwrap();
-
- System::current().stop();
- system.run();
- TestLogHandler::new().exists_log_containing(
- "DEBUG: BlockchainBridge: Received BindMessage; no consuming wallet address specified",
- );
- }
-
#[test]
fn qualified_payables_msg_is_handled_and_new_msg_with_an_added_blockchain_agent_returns_to_accountant(
) {
@@ -667,7 +621,6 @@ mod tests {
Box::new(blockchain_interface),
Box::new(persistent_configuration),
false,
- Some(consuming_wallet.clone()),
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -675,6 +628,7 @@ mod tests {
let qualified_payables = protect_payables_in_test(qualified_payables.clone());
let qualified_payables_msg = QualifiedPayablesMessage {
protected_qualified_payables: qualified_payables.clone(),
+ consuming_wallet: consuming_wallet.clone(),
response_skeleton_opt: Some(ResponseSkeleton {
client_id: 11122,
context_id: 444,
@@ -728,7 +682,6 @@ mod tests {
Box::new(blockchain_interface),
Box::new(persistent_configuration),
false,
- Some(consuming_wallet),
);
subject.logger = Logger::new(test_name);
subject.scan_error_subs_opt = Some(scan_error_recipient);
@@ -739,6 +692,7 @@ mod tests {
last_paid_timestamp: SystemTime::now(),
pending_payable_opt: None,
}]),
+ consuming_wallet,
response_skeleton_opt: Some(ResponseSkeleton {
client_id: 11,
context_id: 2323,
@@ -772,37 +726,6 @@ mod tests {
.exists_log_containing(&format!("WARN: {test_name}: {expected_error_msg}"));
}
- #[test]
- fn handle_qualified_payable_msg_fails_at_missing_consuming_wallet() {
- let blockchain_interface = BlockchainInterfaceMock::default();
- let persistent_configuration = PersistentConfigurationMock::default();
- let mut subject = BlockchainBridge::new(
- Box::new(blockchain_interface),
- Box::new(persistent_configuration),
- false,
- None,
- );
- let request = QualifiedPayablesMessage {
- protected_qualified_payables: protect_payables_in_test(vec![PayableAccount {
- wallet: make_wallet("blah"),
- balance_wei: 4254,
- last_paid_timestamp: SystemTime::now(),
- pending_payable_opt: None,
- }]),
- response_skeleton_opt: None,
- };
-
- let result = subject.handle_qualified_payable_msg(request);
-
- assert_eq!(
- result,
- Err(
- "Cannot inspect available balances for payables while consuming wallet is missing"
- .to_string()
- )
- )
- }
-
#[test]
fn handle_outbound_payments_instructions_sees_payments_happen_and_sends_payment_results_back_to_accountant(
) {
@@ -828,12 +751,10 @@ mod tests {
hash: H256::from("someothertransactionhash".keccak256()),
}),
]));
- let consuming_wallet = make_paying_wallet(b"somewallet");
let subject = BlockchainBridge::new(
Box::new(blockchain_interface_mock),
Box::new(PersistentConfigurationMock::default()),
false,
- Some(consuming_wallet.clone()),
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -917,12 +838,10 @@ mod tests {
let blockchain_interface_mock = BlockchainInterfaceMock::default()
.send_batch_of_payables_result(expected_error.clone());
let persistent_configuration_mock = PersistentConfigurationMock::default();
- let consuming_wallet = make_paying_wallet(b"somewallet");
let subject = BlockchainBridge::new(
Box::new(blockchain_interface_mock),
Box::new(persistent_configuration_mock),
false,
- Some(consuming_wallet),
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -988,13 +907,11 @@ mod tests {
msg: "failure from chronic exhaustion".to_string(),
hashes: vec![transaction_hash],
}));
- let consuming_wallet = make_wallet("somewallet");
let persistent_configuration_mock = PersistentConfigurationMock::new();
let mut subject = BlockchainBridge::new(
Box::new(blockchain_interface_mock),
Box::new(persistent_configuration_mock),
false,
- Some(consuming_wallet.clone()),
);
let checked_accounts = vec![PayableAccount {
wallet: make_wallet("blah"),
@@ -1043,7 +960,6 @@ mod tests {
Box::new(blockchain_interface_mock),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -1104,13 +1020,12 @@ mod tests {
)))
.lower_interface_results(Box::new(lower_interface));
let persistent_config = PersistentConfigurationMock::new()
- .max_block_count_result(Ok(Some(100_000)))
- .start_block_result(Ok(5)); // no set_start_block_result: set_start_block() must not be called
+ .max_block_count_result(Ok(Some(DEFAULT_MAX_BLOCK_COUNT)))
+ .start_block_result(Ok(Some(5))); // no set_start_block_result: set_start_block() must not be called
let mut subject = BlockchainBridge::new(
Box::new(blockchain_interface),
Box::new(persistent_config),
false,
- None,
);
subject.scan_error_subs_opt = Some(scan_error_recipient);
let msg = RetrieveTransactions {
@@ -1130,13 +1045,13 @@ mod tests {
&ScanError {
scan_type: ScanType::Receivables,
response_skeleton_opt: None,
- msg: "Could not retrieve Transactions: QueryFailed(\"we have no luck\")"
- .to_string()
+ msg: "Attempted to retrieve received payments but failed: QueryFailed(\"we have no luck\")".to_string()
}
);
assert_eq!(recording.len(), 1);
TestLogHandler::new().exists_log_containing(
- "WARN: BlockchainBridge: Could not retrieve Transactions: QueryFailed(\"we have no luck\")",
+ "WARN: BlockchainBridge: Attempted to retrieve \
+ received payments but failed: QueryFailed(\"we have no luck\")",
);
}
@@ -1197,7 +1112,6 @@ mod tests {
Box::new(blockchain_interface_mock),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
subject
.pending_payable_confirmation
@@ -1260,7 +1174,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- Some(Wallet::new("mine")),
);
subject
.pending_payable_confirmation
@@ -1321,7 +1234,6 @@ mod tests {
Box::new(blockchain_interface_mock),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
subject
.pending_payable_confirmation
@@ -1366,18 +1278,19 @@ mod tests {
}
#[test]
- fn handle_retrieve_transactions_uses_latest_block_number_upon_get_block_number_error() {
+ fn handle_retrieve_transactions_uses_default_max_block_count_for_ending_block_number_upon_get_block_number_error(
+ ) {
init_test_logging();
let retrieve_transactions_params_arc = Arc::new(Mutex::new(vec![]));
let system = System::new(
- "handle_retrieve_transactions_uses_latest_block_number_upon_get_block_number_error",
+ "handle_retrieve_transactions_uses_default_max_block_count_for_ending_block_number_upon_get_block_number_error",
);
let (accountant, _, accountant_recording_arc) = make_recorder();
let earning_wallet = make_wallet("somewallet");
let amount = 42;
let amount2 = 55;
let expected_transactions = RetrievedBlockchainTransactions {
- new_start_block: 8675309u64,
+ new_start_block: BlockNumber::Number(8675309u64.into()),
transactions: vec![
BlockchainTransaction {
block_number: 7,
@@ -1400,13 +1313,12 @@ mod tests {
.retrieve_transactions_result(Ok(expected_transactions.clone()))
.lower_interface_results(Box::new(lower_interface));
let persistent_config = PersistentConfigurationMock::new()
- .max_block_count_result(Ok(Some(10000u64)))
- .start_block_result(Ok(6));
+ .max_block_count_result(Ok(Some(DEFAULT_MAX_BLOCK_COUNT)))
+ .start_block_result(Ok(Some(6)));
let subject = BlockchainBridge::new(
Box::new(blockchain_interface_mock),
Box::new(persistent_config),
false,
- Some(make_wallet("consuming")),
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -1431,7 +1343,7 @@ mod tests {
*retrieve_transactions_params,
vec![(
BlockNumber::Number(6u64.into()),
- BlockNumber::Number(10006u64.into()),
+ BlockNumber::Number((DEFAULT_MAX_BLOCK_COUNT + 6u64).into()),
earning_wallet
)]
);
@@ -1451,7 +1363,176 @@ mod tests {
}),
}
);
- TestLogHandler::new().exists_log_containing("INFO: BlockchainBridge: Using 'latest' block number instead of a literal number. QueryFailed(\"Failed to read the latest block number\")");
+ TestLogHandler::new().exists_log_containing("DEBUG: BlockchainBridge: Using '100006' ending block number. QueryFailed(\"Failed to read the latest block number\")");
+ }
+
+ #[test]
+ fn handle_retrieve_transactions_when_start_block_number_starts_undefined_in_a_brand_new_database(
+ ) {
+ let retrieve_transactions_params_arc = Arc::new(Mutex::new(vec![]));
+ let system = System::new(
+ "handle_retrieve_transactions_when_start_block_number_starts_undefined_in_a_brand_new_database",
+ );
+ let (accountant, _, accountant_recording_arc) = make_recorder();
+ let earning_wallet = make_wallet("somewallet");
+ let amount = 42;
+ let amount2 = 55;
+ let expected_transactions = RetrievedBlockchainTransactions {
+ new_start_block: BlockNumber::Number(8675309u64.into()),
+ transactions: vec![
+ BlockchainTransaction {
+ block_number: 8675308u64,
+ from: earning_wallet.clone(),
+ wei_amount: amount,
+ },
+ BlockchainTransaction {
+ block_number: 8675309u64,
+ from: earning_wallet.clone(),
+ wei_amount: amount2,
+ },
+ ],
+ };
+ let lower_interface = LowBlockchainIntMock::default().get_block_number_result(
+ LatestBlockNumber::Err(BlockchainError::QueryFailed(
+ "\"Failed to read the latest block number\"".to_string(),
+ )),
+ );
+ let blockchain_interface_mock = BlockchainInterfaceMock::default()
+ .retrieve_transactions_params(&retrieve_transactions_params_arc)
+ .retrieve_transactions_result(Ok(expected_transactions.clone()))
+ .lower_interface_results(Box::new(lower_interface));
+ let persistent_config = PersistentConfigurationMock::new()
+ .max_block_count_result(Ok(Some(DEFAULT_MAX_BLOCK_COUNT)))
+ .start_block_result(Ok(None));
+ let subject = BlockchainBridge::new(
+ Box::new(blockchain_interface_mock),
+ Box::new(persistent_config),
+ false,
+ );
+ let addr = subject.start();
+ let subject_subs = BlockchainBridge::make_subs_from(&addr);
+ let peer_actors = peer_actors_builder().accountant(accountant).build();
+ send_bind_message!(subject_subs, peer_actors);
+ let retrieve_transactions = RetrieveTransactions {
+ recipient: earning_wallet.clone(),
+ response_skeleton_opt: Some(ResponseSkeleton {
+ client_id: 1234,
+ context_id: 4321,
+ }),
+ };
+ let before = SystemTime::now();
+
+ let _ = addr.try_send(retrieve_transactions).unwrap();
+
+ System::current().stop();
+ system.run();
+ let after = SystemTime::now();
+ let retrieve_transactions_params = retrieve_transactions_params_arc.lock().unwrap();
+ assert_eq!(
+ *retrieve_transactions_params,
+ vec![(BlockNumber::Latest, BlockNumber::Latest, earning_wallet)]
+ );
+ let accountant_received_payment = accountant_recording_arc.lock().unwrap();
+ assert_eq!(accountant_received_payment.len(), 1);
+ let received_payments = accountant_received_payment.get_record::(0);
+ check_timestamp(before, received_payments.timestamp, after);
+ assert_eq!(
+ received_payments,
+ &ReceivedPayments {
+ timestamp: received_payments.timestamp,
+ payments: expected_transactions.transactions,
+ new_start_block: 8675309u64,
+ response_skeleton_opt: Some(ResponseSkeleton {
+ client_id: 1234,
+ context_id: 4321
+ }),
+ }
+ );
+ }
+
+ #[test]
+ fn handle_retrieve_transactions_when_get_block_number_fails_uses_latest_for_start_and_end_block(
+ ) {
+ let retrieve_transactions_params_arc = Arc::new(Mutex::new(vec![]));
+ let earning_wallet = make_wallet("somewallet");
+ let amount = 42;
+ let amount2 = 55;
+ let expected_transactions = RetrievedBlockchainTransactions {
+ new_start_block: BlockNumber::Number(98765u64.into()),
+ transactions: vec![
+ BlockchainTransaction {
+ block_number: 77,
+ from: earning_wallet.clone(),
+ wei_amount: amount,
+ },
+ BlockchainTransaction {
+ block_number: 99,
+ from: earning_wallet.clone(),
+ wei_amount: amount2,
+ },
+ ],
+ };
+
+ let system = System::new(
+ "handle_retrieve_transactions_when_get_block_number_fails_uses_latest_for_start_and_end_block",
+ );
+ let (accountant, _, accountant_recording_arc) = make_recorder();
+ let persistent_config = PersistentConfigurationMock::new()
+ .max_block_count_result(Ok(Some(DEFAULT_MAX_BLOCK_COUNT)))
+ .start_block_result(Ok(None));
+ let latest_block_number = LatestBlockNumber::Err(BlockchainError::QueryFailed(
+ "Failed to read from block chain service".to_string(),
+ ));
+ let lower_interface =
+ LowBlockchainIntMock::default().get_block_number_result(latest_block_number);
+ let blockchain_interface = BlockchainInterfaceMock::default()
+ .retrieve_transactions_params(&retrieve_transactions_params_arc)
+ .retrieve_transactions_result(Ok(expected_transactions.clone()))
+ .lower_interface_results(Box::new(lower_interface));
+ let subject = BlockchainBridge::new(
+ Box::new(blockchain_interface),
+ Box::new(persistent_config),
+ false,
+ );
+ let addr = subject.start();
+ let subject_subs = BlockchainBridge::make_subs_from(&addr);
+ let peer_actors = peer_actors_builder().accountant(accountant).build();
+ send_bind_message!(subject_subs, peer_actors);
+ let retrieve_transactions = RetrieveTransactions {
+ recipient: earning_wallet.clone(),
+ response_skeleton_opt: Some(ResponseSkeleton {
+ client_id: 1234,
+ context_id: 4321,
+ }),
+ };
+ let before = SystemTime::now();
+
+ let _ = addr.try_send(retrieve_transactions).unwrap();
+
+ System::current().stop();
+ system.run();
+ let after = SystemTime::now();
+ let retrieve_transactions_params = retrieve_transactions_params_arc.lock().unwrap();
+ assert_eq!(
+ *retrieve_transactions_params,
+ vec![(BlockNumber::Latest, BlockNumber::Latest, earning_wallet)]
+ );
+ let accountant_received_payment = accountant_recording_arc.lock().unwrap();
+ assert_eq!(accountant_received_payment.len(), 1);
+ let received_payments = accountant_received_payment.get_record::(0);
+ check_timestamp(before, received_payments.timestamp, after);
+ assert_eq!(
+ received_payments,
+ &ReceivedPayments {
+ timestamp: received_payments.timestamp,
+ payments: expected_transactions.transactions,
+ new_start_block: 98765,
+ response_skeleton_opt: Some(ResponseSkeleton {
+ client_id: 1234,
+ context_id: 4321
+ }),
+ }
+ );
}
#[test]
@@ -1464,7 +1545,7 @@ mod tests {
let amount = 42;
let amount2 = 55;
let expected_transactions = RetrievedBlockchainTransactions {
- new_start_block: 9876,
+ new_start_block: BlockNumber::Number(9876.into()),
transactions: vec![
BlockchainTransaction {
block_number: 7,
@@ -1487,12 +1568,11 @@ mod tests {
.lower_interface_results(Box::new(lower_interface));
let persistent_config = PersistentConfigurationMock::new()
.max_block_count_result(Ok(Some(10000u64)))
- .start_block_result(Ok(6));
+ .start_block_result(Ok(Some(6)));
let subject = BlockchainBridge::new(
Box::new(blockchain_interface_mock),
Box::new(persistent_config),
false,
- Some(make_wallet("consuming")),
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -1546,13 +1626,13 @@ mod tests {
LowBlockchainIntMock::default().get_block_number_result(Ok(0u64.into()));
let blockchain_interface_mock = BlockchainInterfaceMock::default()
.retrieve_transactions_result(Ok(RetrievedBlockchainTransactions {
- new_start_block: 7,
+ new_start_block: BlockNumber::Number(7.into()),
transactions: vec![],
}))
.lower_interface_results(Box::new(lower_interface));
let persistent_config = PersistentConfigurationMock::new()
.max_block_count_result(Ok(Some(10000u64)))
- .start_block_result(Ok(6));
+ .start_block_result(Ok(Some(6)));
let (accountant, _, accountant_recording_arc) = make_recorder();
let system = System::new(
"processing_of_received_payments_continues_even_if_no_payments_are_detected",
@@ -1561,7 +1641,6 @@ mod tests {
Box::new(blockchain_interface_mock),
Box::new(persistent_config),
false,
- None, //not needed in this test
);
let addr = subject.start();
let subject_subs = BlockchainBridge::make_subs_from(&addr);
@@ -1615,7 +1694,6 @@ mod tests {
Box::new(blockchain_interface),
Box::new(persistent_config),
false,
- None, //not needed in this test
);
let retrieve_transactions = RetrieveTransactions {
recipient: make_wallet("somewallet"),
@@ -1625,38 +1703,6 @@ mod tests {
let _ = subject.handle_retrieve_transactions(retrieve_transactions);
}
- #[test]
- #[should_panic(expected = "Writing max_block_count failed: QueryFailed")]
- fn handle_retrieve_transactions_panics_if_writing_max_block_count_failed() {
- let retrieve_transactions_params_arc = Arc::new(Mutex::new(vec![]));
- let earning_wallet = make_wallet("somewallet");
- let latest_block_number = LatestBlockNumber::Ok(1024u64.into());
- let lower_interface =
- LowBlockchainIntMock::default().get_block_number_result(latest_block_number);
- let blockchain_interface =
- BlockchainInterfaceMock::default()
- .retrieve_transactions_params(&retrieve_transactions_params_arc)
- .retrieve_transactions_result(Err(BlockchainError::QueryFailed("RPC error: Error { code: ServerError(-32005), message: \"eth_getLogs is limited to 1024 block range. Please check the parameter requirements at https://docs.blockpi.io/documentations/api-reference\", data: None }".to_string())))
- .lower_interface_results(Box::new(lower_interface));
- let persistent_config = PersistentConfigurationMock::new()
- .max_block_count_result(Ok(Some(10000u64)))
- .start_block_result(Ok(6))
- .set_max_block_count_result(Err(PersistentConfigError::TransactionError));
- let mut subject = BlockchainBridge::new(
- Box::new(blockchain_interface),
- Box::new(persistent_config),
- false,
- Some(make_wallet("consuming")),
- );
-
- let retrieve_transactions = RetrieveTransactions {
- recipient: earning_wallet,
- response_skeleton_opt: None,
- };
-
- let _ = subject.handle_retrieve_transactions(retrieve_transactions);
- }
-
fn success_handler(
_bcb: &mut BlockchainBridge,
_msg: RetrieveTransactions,
@@ -1678,7 +1724,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::new()),
false,
- None, //not needed in this test
);
let system = System::new("test");
subject.scan_error_subs_opt = Some(accountant.start().recipient());
@@ -1710,7 +1755,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::new()),
false,
- None, //not needed in this test
);
let system = System::new("test");
subject.scan_error_subs_opt = Some(accountant.start().recipient());
@@ -1749,7 +1793,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::new()),
false,
- None, //not needed in this test
);
let system = System::new("test");
subject.scan_error_subs_opt = Some(accountant.start().recipient());
@@ -1794,7 +1837,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
crashable,
- None,
);
prove_that_crash_request_handler_is_hooked_up(subject, CRASH_KEY);
@@ -1807,7 +1849,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
@@ -1821,14 +1862,13 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
assert_eq!(Some(100000u64), max_block_count);
}
/*
- POKT (Polygon mainnet and mumbai)
+ POKT (Polygon mainnet and amoy)
{"jsonrpc":"2.0","id":7,"error":{"message":"You cannot query logs for more than 100000 blocks at once.","code":-32064}}
*/
/*
@@ -1842,7 +1882,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
@@ -1860,7 +1899,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
@@ -1878,7 +1916,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
@@ -1898,13 +1935,25 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
assert_eq!(None, max_block_count);
}
+ #[test]
+ fn extract_max_block_range_for_nodies_error_response() {
+ let result = BlockchainError::QueryFailed("RPC error: Error { code: InvalidParams, message: \"query exceeds max block range 100000\", data: None }".to_string());
+ let subject = BlockchainBridge::new(
+ Box::new(BlockchainInterfaceMock::default()),
+ Box::new(PersistentConfigurationMock::default()),
+ false,
+ );
+ let max_block_count = subject.extract_max_block_count(result);
+
+ assert_eq!(Some(100000), max_block_count);
+ }
+
#[test]
fn extract_max_block_range_for_expected_batch_got_single_error_response() {
let result = BlockchainError::QueryFailed(
@@ -1914,7 +1963,6 @@ mod tests {
Box::new(BlockchainInterfaceMock::default()),
Box::new(PersistentConfigurationMock::default()),
false,
- None,
);
let max_block_count = subject.extract_max_block_count(result);
diff --git a/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs
index 083f75822..a4425a82f 100644
--- a/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs
+++ b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs
@@ -119,12 +119,12 @@ where
.build();
let fallback_start_block_number = match end_block {
- BlockNumber::Number(eb) => eb.as_u64(),
+ BlockNumber::Number(eb) => Some(eb.as_u64()),
_ => {
if let BlockNumber::Number(start_block_number) = start_block {
- start_block_number.as_u64() + 1u64
+ Some(start_block_number.as_u64() + 1u64)
} else {
- panic!("start_block of Latest, Earliest, and Pending are not supported");
+ None
}
}
};
@@ -134,15 +134,15 @@ where
let logger = self.logger.clone();
match self.web3_batch.transport().submit_batch().wait() {
Ok(_) => {
- let response_block_number = match block_request.wait() {
+ let response_block_number_opt = match block_request.wait() {
Ok(block_nbr) => {
debug!(logger, "Latest block number: {}", block_nbr.as_u64());
- block_nbr.as_u64()
+ Some(block_nbr.as_u64())
}
Err(_) => {
debug!(
logger,
- "Using fallback block number: {}", fallback_start_block_number
+ "Using fallback block number: {:?}", fallback_start_block_number
);
fallback_start_block_number
}
@@ -178,16 +178,18 @@ where
// was not successful.
let transaction_max_block_number = self
.find_largest_transaction_block_number(
- response_block_number,
+ response_block_number_opt,
&transactions,
);
debug!(
logger,
- "Discovered transaction max block nbr: {}",
+ "Discovered transaction max block nbr: {:?}",
transaction_max_block_number
);
Ok(RetrievedBlockchainTransactions {
- new_start_block: 1u64 + transaction_max_block_number,
+ new_start_block: transaction_max_block_number
+ .map(|nsb| BlockNumber::Number((1u64 + nsb).into()))
+ .unwrap_or(BlockNumber::Latest),
transactions,
})
}
@@ -579,7 +581,9 @@ where
fn web3_gas_limit_const_part(chain: Chain) -> u64 {
match chain {
Chain::EthMainnet | Chain::EthRopsten | Chain::Dev => 55_000,
- Chain::PolyMainnet | Chain::PolyMumbai => 70_000,
+ Chain::PolyMainnet | Chain::PolyAmoy | Chain::BaseMainnet | Chain::BaseSepolia => {
+ 70_000
+ }
}
}
@@ -601,15 +605,18 @@ where
fn find_largest_transaction_block_number(
&self,
- response_block_number: u64,
+ response_block_number: Option,
transactions: &[BlockchainTransaction],
- ) -> u64 {
+ ) -> Option {
if transactions.is_empty() {
response_block_number
} else {
transactions
.iter()
- .fold(response_block_number, |a, b| a.max(b.block_number))
+ .fold(response_block_number.unwrap_or(0u64), |a, b| {
+ a.max(b.block_number)
+ })
+ .into()
}
}
}
@@ -676,6 +683,7 @@ mod tests {
BlockchainTransaction, RpcPayablesFailure,
};
use indoc::indoc;
+ use sodiumoxide::hex;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::time::SystemTime;
@@ -830,7 +838,7 @@ mod tests {
assert_eq!(
result,
RetrievedBlockchainTransactions {
- new_start_block: 0x4be664,
+ new_start_block: BlockNumber::Number(0x4be664.into()),
transactions: vec![
BlockchainTransaction {
block_number: 0x4be663,
@@ -892,7 +900,7 @@ mod tests {
assert_eq!(
result,
RetrievedBlockchainTransactions {
- new_start_block: 1 + end_block_nbr,
+ new_start_block: BlockNumber::Number((1 + end_block_nbr).into()),
transactions: vec![]
}
);
@@ -1001,7 +1009,7 @@ mod tests {
assert_eq!(
result,
Ok(RetrievedBlockchainTransactions {
- new_start_block: 1 + end_block_nbr,
+ new_start_block: BlockNumber::Number((1 + end_block_nbr).into()),
transactions: vec![]
})
);
@@ -1043,7 +1051,39 @@ mod tests {
assert_eq!(
result,
Ok(RetrievedBlockchainTransactions {
- new_start_block: 1 + expected_fallback_start_block,
+ new_start_block: BlockNumber::Number((1 + expected_fallback_start_block).into()),
+ transactions: vec![]
+ })
+ );
+ }
+
+ #[test]
+ fn blockchain_interface_retrieve_transactions_start_and_end_blocks_can_be_latest() {
+ let port = find_free_port();
+ let contains_error_causing_to_pick_fallback_value = br#"[{"jsonrpc":"2.0","id":1,"result":"error"},{"jsonrpc":"2.0","id":2,"result":[{"address":"0xcd6c588e005032dd882cd43bf53a32129be81302","blockHash":"0x1a24b9169cbaec3f6effa1f600b70c7ab9e8e86db44062b49132a4415d26732a","data":"0x0000000000000000000000000000000000000000000000000010000000000000","logIndex":"0x0","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000003f69f9efd4f2592fd70be8c32ecd9dce71c472fc","0x000000000000000000000000adc1853c7859369639eb414b6342b36288fe6092"],"transactionHash":"0x955cec6ac4f832911ab894ce16aa22c3003f46deff3f7165b32700d2f5ff0681","transactionIndex":"0x0"}]}]"#;
+ let _test_server = TestServer::start(
+ port,
+ vec![contains_error_causing_to_pick_fallback_value.to_vec()],
+ );
+ let (event_loop_handle, transport) = Http::with_max_parallel(
+ &format!("http://{}:{}", &Ipv4Addr::LOCALHOST, port),
+ REQUESTS_IN_PARALLEL,
+ )
+ .unwrap();
+ let chain = TEST_DEFAULT_CHAIN;
+ let subject = BlockchainInterfaceWeb3::new(transport, event_loop_handle, chain);
+
+ let result = subject.retrieve_transactions(
+ BlockNumber::Latest,
+ BlockNumber::Latest,
+ &make_wallet("earning-wallet"),
+ );
+
+ let expected_new_start_block = BlockNumber::Latest;
+ assert_eq!(
+ result,
+ Ok(RetrievedBlockchainTransactions {
+ new_start_block: expected_new_start_block,
transactions: vec![]
})
);
@@ -1107,7 +1147,7 @@ mod tests {
#[test]
fn build_of_the_blockchain_agent_fails_on_fetching_gas_price() {
- let chain = Chain::PolyMumbai;
+ let chain = Chain::PolyAmoy;
let wallet = make_wallet("abc");
let persistent_config = PersistentConfigurationMock::new().gas_price_result(Err(
PersistentConfigError::UninterpretableValue("booga".to_string()),
@@ -1218,7 +1258,7 @@ mod tests {
//exercising also the layer of web3 functions, but the transport layer is mocked
init_test_logging();
let send_batch_params_arc = Arc::new(Mutex::new(vec![]));
- //we compute the hashes ourselves during the batch preparation and so we don't care about
+ //we compute the hashes ourselves during the batch preparation, and so we don't care about
//the same ones coming back with the response; we use the returned OKs as indicators of success only.
//Any eventual rpc errors brought back are processed as well...
let expected_batch_responses = vec![
@@ -1281,9 +1321,14 @@ mod tests {
Call::MethodCall(MethodCall {
jsonrpc: Some(V2),
method: "eth_sendRawTransaction".to_string(),
- params: Params::Array(vec![Value::String("0xf8a906851bf08eb00082db6894384dec25e03f94931767ce4c3556168468ba24c380b844a9059cbb000\
- 00000000000000000000000000000000000000000000000000000773132330000000000000000000000000000000000000000000000000c7d713b49da00002aa060b9f375c06f56\
- 41951606643d76ef999d32ae02f6b6cd62c9275ebdaa36a390a0199c3d8644c428efd5e0e0698c031172ac6873037d90dcca36a1fbf2e67960ff".to_string())]),
+ params: Params::Array(vec![Value::String(
+ "0xf8a906851bf08eb00082db6894384de\
+ c25e03f94931767ce4c3556168468ba24c380b844a9059cbb000000000000000000000000000000000000000000\
+ 00000000000000773132330000000000000000000000000000000000000000000000000c7d713b49da00002aa06\
+ 0b9f375c06f5641951606643d76ef999d32ae02f6b6cd62c9275ebdaa36a390a0199c3d8644c428efd5e0e0698c\
+ 031172ac6873037d90dcca36a1fbf2e67960ff"
+ .to_string()
+ )]),
id: Id::Num(1)
})
),
@@ -1292,9 +1337,14 @@ mod tests {
Call::MethodCall(MethodCall {
jsonrpc: Some(V2),
method: "eth_sendRawTransaction".to_string(),
- params: Params::Array(vec![Value::String("0xf8a907851bf08eb00082dae894384dec25e03f94931767ce4c3556168468ba24c380b844a9059cbb000\
- 000000000000000000000000000000000000000000000000000007735353500000000000000000000000000000000000000000000000000000000075bcd1529a00e61352bb2ac9b\
- 32b411206250f219b35cdc85db679f3e2416daac4f730a12f1a02c2ad62759d86942f3af2b8915ecfbaa58268010e00d32c18a49a9fc3b9bd20a".to_string())]),
+ params: Params::Array(vec![Value::String(
+ "0xf8a907851bf08eb00082dae894384de\
+ c25e03f94931767ce4c3556168468ba24c380b844a9059cbb000000000000000000000000000000000000000000\
+ 000000000000007735353500000000000000000000000000000000000000000000000000000000075bcd1529a00\
+ e61352bb2ac9b32b411206250f219b35cdc85db679f3e2416daac4f730a12f1a02c2ad62759d86942f3af2b8915\
+ ecfbaa58268010e00d32c18a49a9fc3b9bd20a"
+ .to_string()
+ )]),
id: Id::Num(1)
})
),
@@ -1303,9 +1353,14 @@ mod tests {
Call::MethodCall(MethodCall {
jsonrpc: Some(V2),
method: "eth_sendRawTransaction".to_string(),
- params: Params::Array(vec![Value::String("0xf8a908851bf08eb00082db6894384dec25e03f94931767ce4c3556168468ba24c380b844a9059cbb000\
- 0000000000000000000000000000000000000000000000000000077393837000000000000000000000000000000000000000000000000007680cd2f2d34002aa02d300cc8ba7b63\
- b0147727c824a54a7db9ec083273be52a32bdca72657a3e310a042a17224b35e7036d84976a23fbe8b1a488b2bcabed1e4a2b0b03f0c9bbc38e9".to_string())]),
+ params: Params::Array(vec![Value::String(
+ "0xf8a908851bf08eb00082db6894384de\
+ c25e03f94931767ce4c3556168468ba24c380b844a9059cbb000000000000000000000000000000000000000000\
+ 0000000000000077393837000000000000000000000000000000000000000000000000007680cd2f2d34002aa02\
+ d300cc8ba7b63b0147727c824a54a7db9ec083273be52a32bdca72657a3e310a042a17224b35e7036d84976a23f\
+ be8b1a488b2bcabed1e4a2b0b03f0c9bbc38e9"
+ .to_string()
+ )]),
id: Id::Num(1)
})
)
@@ -1613,8 +1668,9 @@ mod tests {
Subject::web3_gas_limit_const_part(Chain::PolyMainnet),
70_000
);
+ assert_eq!(Subject::web3_gas_limit_const_part(Chain::PolyAmoy), 70_000);
assert_eq!(
- Subject::web3_gas_limit_const_part(Chain::PolyMumbai),
+ Subject::web3_gas_limit_const_part(Chain::BaseSepolia),
70_000
);
assert_eq!(Subject::web3_gas_limit_const_part(Chain::Dev), 55_000);
@@ -1683,7 +1739,7 @@ mod tests {
#[test]
fn signing_error_terminates_iteration_over_accounts_and_propagates_it_all_way_up_and_out() {
let transport = TestTransport::default();
- let chain = Chain::PolyMumbai;
+ let chain = Chain::PolyAmoy;
let batch_payable_tools = BatchPayableToolsMock::::default()
.sign_transaction_result(Err(Web3Error::Signing(
secp256k1secrets::Error::InvalidSecretKey,
@@ -1749,7 +1805,7 @@ mod tests {
.batch_wide_timestamp_result(SystemTime::now())
.submit_batch_result(Err(Web3Error::Transport("Transaction crashed".to_string())));
let consuming_wallet_secret_raw_bytes = b"okay-wallet";
- let chain = Chain::PolyMumbai;
+ let chain = Chain::PolyAmoy;
let mut subject =
BlockchainInterfaceWeb3::new(transport, make_fake_event_loop_handle(), chain);
subject.batch_payable_tools = Box::new(batch_payable_tools);
@@ -1781,7 +1837,7 @@ mod tests {
secp256k1secrets::Error::InvalidSecretKey,
)));
let consuming_wallet_secret_raw_bytes = b"okay-wallet";
- let chain = Chain::PolyMumbai;
+ let chain = Chain::PolyAmoy;
let mut subject =
BlockchainInterfaceWeb3::new(transport, make_fake_event_loop_handle(), chain);
subject.batch_payable_tools = Box::new(batch_payable_tools);
@@ -1801,10 +1857,6 @@ mod tests {
);
}
- const TEST_PAYMENT_AMOUNT: u128 = 1_000_000_000_000;
- const TEST_GAS_PRICE_ETH: u64 = 110;
- const TEST_GAS_PRICE_POLYGON: u64 = 50;
-
fn test_consuming_wallet_with_secret() -> Wallet {
let key_pair = Bip32EncryptionKeyProvider::from_raw_secret(
&decode_hex("97923d8fd8de4a00f912bfb77ef483141dec551bd73ea59343ef5c4aac965d04")
@@ -1832,12 +1884,16 @@ mod tests {
let recipient_wallet = test_recipient_wallet();
let nonce_correct_type = U256::from(nonce);
let gas_price = match chain {
- Chain::EthMainnet | Chain::EthRopsten | Chain::Dev => TEST_GAS_PRICE_ETH,
- Chain::PolyMainnet | Chain::PolyMumbai => TEST_GAS_PRICE_POLYGON,
+ Chain::EthMainnet | Chain::EthRopsten | Chain::Dev => 110,
+ Chain::PolyMainnet | Chain::PolyAmoy => 55,
+ // It performs on even cheaper fees, but we're
+ // limited by the units here
+ Chain::BaseMainnet | Chain::BaseSepolia => 1,
};
+ let payment_size_wei = gwei_to_wei(1_000_u64);
let payable_account = make_payable_account_with_wallet_and_balance_and_timestamp_opt(
recipient_wallet,
- TEST_PAYMENT_AMOUNT,
+ payment_size_wei,
None,
);
@@ -1852,77 +1908,106 @@ mod tests {
.unwrap();
let byte_set_to_compare = signed_transaction.raw_transaction.0;
- assert_eq!(byte_set_to_compare.as_slice(), template)
+ assert_eq!(
+ byte_set_to_compare,
+ template,
+ "Actual signed transaction {} does not match {} as expected",
+ hex::encode(byte_set_to_compare.clone()),
+ hex::encode(template.to_vec())
+ )
}
- //with a real confirmation through a transaction sent with this data to the network
+ // Transaction with this input was verified on the test network
#[test]
- fn web3_interface_signing_a_transaction_works_for_polygon_mumbai() {
- let chain = Chain::PolyMumbai;
- let nonce = 5;
- // signed_transaction_data changed after we changed the contract address of polygon matic
- let signed_transaction_data = "f8ad05850ba43b740083011980949b27034acabd44223fb23d628ba4849867ce1db280b844a9059cbb0000000000000000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b000000000000000000000000000000000000000000000000000000e8d4a5100083027126a09fdbbd7064d3b7240f5422b2164aaa13d62f0946a683d82ee26f97f242570d90a077b49dbb408c20d73e0666ba0a77ac888bf7a9cb14824a5f35c97217b9bc0a5a";
+ fn web3_interface_signing_a_transaction_works_for_polygon_amoy() {
+ let chain = Chain::PolyAmoy;
+ let nonce = 4;
+ let signed_transaction_data = "\
+ f8ad04850cce4166008301198094d98c3ebd6b7f9b7cda2449ecac00d1e5f47a819380b844a9059cbb000000000\
+ 0000000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b000000000000000000000000000000000000\
+ 000000000000000000e8d4a5100083027127a0ddd78a41c42b7a409c281292f7c6aedefab8b461d87371fe402b4\
+ b0804a092f2a04b1b599ac2c1ff07bb3d40d3698c454691c3b70d99f1e5d840c852e968c96a10";
+ let in_bytes = decode_hex(signed_transaction_data).unwrap();
+
+ assert_that_signed_transactions_agrees_with_template(chain, nonce, &in_bytes)
+ }
+ #[test]
+ fn web3_interface_signing_a_transaction_works_for_base_sepolia() {
+ let chain = Chain::BaseSepolia;
+ let nonce = 2;
+ let signed_transaction_data = "\
+ f8ac02843b9aca008301198094898e1ce720084a902bc37dd822ed6d6a5f027e1080b844a9059cbb00000000000\
+ 00000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b00000000000000000000000000000000000000\
+ 0000000000000000e8d4a510008302948ca07b57223b566ade08ec817770c8b9ae94373edbefc13372c3463cf7b\
+ 6ce542231a020991f2ff180a12cbc2745465a4e710da294b890901a3887519b191c3a69cd4f";
let in_bytes = decode_hex(signed_transaction_data).unwrap();
assert_that_signed_transactions_agrees_with_template(chain, nonce, &in_bytes)
}
- //with a real confirmation through a transaction sent with this data to the network
+ // Transaction with this input was verified on the test network
#[test]
fn web3_interface_signing_a_transaction_works_for_eth_ropsten() {
let chain = Chain::EthRopsten;
- let nonce = 1; //must stay like this!
- let signed_transaction_data = "f8a90185199c82cc0082dee894384dec25e03f94931767ce4c3556168468ba24c380b844a9059cbb0000000000000000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b000000000000000000000000000000000000000000000000000000e8d4a510002aa0635fbb3652e1c3063afac6ffdf47220e0431825015aef7daff9251694e449bfca00b2ed6d556bd030ac75291bf58817da15a891cd027a4c261bb80b51f33b78adf";
+ let nonce = 1;
+ let signed_transaction_data = "\
+ f8a90185199c82cc0082dee894384dec25e03f94931767ce4c3556168468ba24c380b844a9059cbb00000000000\
+ 00000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b00000000000000000000000000000000000000\
+ 0000000000000000e8d4a510002aa0635fbb3652e1c3063afac6ffdf47220e0431825015aef7daff9251694e449\
+ bfca00b2ed6d556bd030ac75291bf58817da15a891cd027a4c261bb80b51f33b78adf";
let in_bytes = decode_hex(signed_transaction_data).unwrap();
assert_that_signed_transactions_agrees_with_template(chain, nonce, &in_bytes)
}
- //not confirmed on the real network
+ // Unconfirmed on the real network
#[test]
fn web3_interface_signing_a_transaction_for_polygon_mainnet() {
let chain = Chain::PolyMainnet;
let nonce = 10;
- //generated locally
- let signed_transaction_data = [
- 248, 172, 10, 133, 11, 164, 59, 116, 0, 131, 1, 25, 128, 148, 238, 154, 53, 47, 106,
- 172, 74, 241, 165, 185, 244, 103, 246, 169, 62, 15, 251, 233, 221, 53, 128, 184, 68,
- 169, 5, 156, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 136, 223, 118, 187, 217,
- 160, 199, 195, 229, 191, 15, 119, 187, 40, 198, 10, 22, 122, 123, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 212, 165, 16, 0, 130,
- 1, 53, 160, 7, 203, 40, 44, 202, 233, 15, 5, 64, 218, 199, 239, 94, 126, 152, 2, 108,
- 30, 157, 75, 124, 129, 117, 27, 109, 163, 132, 27, 11, 123, 137, 10, 160, 18, 170, 130,
- 198, 73, 190, 158, 235, 0, 77, 118, 213, 244, 229, 225, 143, 156, 214, 219, 204, 193,
- 155, 199, 164, 162, 31, 134, 51, 139, 130, 152, 104,
- ];
+ let signed_transaction_data = "f8ac0a850cce4166008301198094ee9a352f6aac4af1a5b9f467f6a\
+ 93e0ffbe9dd3580b844a9059cbb0000000000000000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b\
+ 000000000000000000000000000000000000000000000000000000e8d4a51000820135a0c89f4dca80c3437a23c\
+ c1a41ab59fd5206b0c0e1293d975242e8482c44838c75a075429a84b761db83d648dc4298480f6b2cedc110c134\
+ 065ed8955e66c7504469";
+ let in_bytes = decode_hex(signed_transaction_data).unwrap();
- assert_that_signed_transactions_agrees_with_template(chain, nonce, &signed_transaction_data)
+ assert_that_signed_transactions_agrees_with_template(chain, nonce, &in_bytes)
}
- //not confirmed on the real network
+ // Unconfirmed on the real network
#[test]
fn web3_interface_signing_a_transaction_for_eth_mainnet() {
let chain = Chain::EthMainnet;
let nonce = 10;
- //generated locally
- let signed_transaction_data = [
- 248, 169, 10, 133, 25, 156, 130, 204, 0, 130, 222, 232, 148, 6, 243, 195, 35, 240, 35,
- 140, 114, 191, 53, 1, 16, 113, 242, 181, 183, 244, 58, 5, 76, 128, 184, 68, 169, 5,
- 156, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 136, 223, 118, 187, 217, 160, 199,
- 195, 229, 191, 15, 119, 187, 40, 198, 10, 22, 122, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 212, 165, 16, 0, 38, 160, 199,
- 155, 76, 106, 39, 227, 3, 151, 90, 117, 245, 211, 86, 98, 187, 117, 120, 103, 165, 131,
- 99, 72, 36, 211, 10, 224, 252, 104, 51, 200, 230, 158, 160, 84, 18, 140, 248, 119, 22,
- 193, 14, 148, 253, 48, 59, 185, 11, 38, 152, 103, 150, 120, 60, 74, 56, 159, 206, 22,
- 15, 73, 173, 153, 11, 76, 74,
- ];
+ let signed_transaction_data = "f8a90a85199c82cc0082dee89406f3c323f0238c72bf35011071f2b\
+ 5b7f43a054c80b844a9059cbb0000000000000000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b00\
+ 0000000000000000000000000000000000000000000000000000e8d4a5100026a0c79b4c6a27e303975a75f5d35\
+ 662bb757867a583634824d30ae0fc6833c8e69ea054128cf87716c10e94fd303bb90b26986796783c4a389fce16\
+ 0f49ad990b4c4a";
+ let in_bytes = decode_hex(signed_transaction_data).unwrap();
+
+ assert_that_signed_transactions_agrees_with_template(chain, nonce, &in_bytes)
+ }
+
+ // Unconfirmed on the real network
+ #[test]
+ fn web3_interface_signing_a_transaction_for_base_mainnet() {
+ let chain = Chain::BaseMainnet;
+ let nonce = 124;
+ let signed_transaction_data = "f8ab7c843b9aca00830119809445d9c101a3870ca5024582fd788f4\
+ e1e8f7971c380b844a9059cbb0000000000000000000000007788df76bbd9a0c7c3e5bf0f77bb28c60a167a7b00\
+ 0000000000000000000000000000000000000000000000000000e8d4a5100082422da0587b5f8401225d5cf6267\
+ 6f51f376f085805851e2e59c5253eb2834612295bdba05b6963872bac7eeafb38191079e8c8df919c193839022b\
+ d57b91ace5a8638034";
+ let in_bytes = decode_hex(signed_transaction_data).unwrap();
- assert_that_signed_transactions_agrees_with_template(chain, nonce, &signed_transaction_data)
+ assert_that_signed_transactions_agrees_with_template(chain, nonce, &in_bytes)
}
- //an adapted test from old times when we had our own signing method
- //I don't have data for the new chains so I omit them in this kind of tests
+ // Adapted test from old times when we had our own signing method.
+ // Don't have data for new chains, so I omit them in this kind of tests
#[test]
fn signs_various_transactions_for_eth_mainnet() {
let signatures = &[
@@ -1955,8 +2040,8 @@ mod tests {
assert_signature(Chain::EthMainnet, signatures)
}
- //an adapted test from old times when we had our own signing method
- //I don't have data for the new chains so I omit them in this kind of tests
+ // Adapted test from old times when we had our own signing method.
+ // Don't have data for new chains, so I omit them in this kind of tests
#[test]
fn signs_various_transactions_for_ropsten() {
let signatures = &[
diff --git a/node/src/blockchain/blockchain_interface/data_structures/mod.rs b/node/src/blockchain/blockchain_interface/data_structures/mod.rs
index d1d785aae..d8b86d5d9 100644
--- a/node/src/blockchain/blockchain_interface/data_structures/mod.rs
+++ b/node/src/blockchain/blockchain_interface/data_structures/mod.rs
@@ -3,7 +3,7 @@
pub mod errors;
use crate::accountant::db_access_objects::pending_payable_dao::PendingPayable;
use crate::sub_lib::wallet::Wallet;
-use web3::types::H256;
+use web3::types::{BlockNumber, H256};
use web3::Error;
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -13,9 +13,9 @@ pub struct BlockchainTransaction {
pub wei_amount: u128,
}
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq)]
pub struct RetrievedBlockchainTransactions {
- pub new_start_block: u64,
+ pub new_start_block: BlockNumber,
pub transactions: Vec,
}
diff --git a/node/src/blockchain/test_utils.rs b/node/src/blockchain/test_utils.rs
index 4a8f4ecd6..16f7d21da 100644
--- a/node/src/blockchain/test_utils.rs
+++ b/node/src/blockchain/test_utils.rs
@@ -331,7 +331,7 @@ pub fn all_chains() -> [Chain; 4] {
[
Chain::EthMainnet,
Chain::PolyMainnet,
- Chain::PolyMumbai,
+ Chain::PolyAmoy,
Chain::Dev,
]
}
diff --git a/node/src/bootstrapper.rs b/node/src/bootstrapper.rs
index f1ece6d54..fccdf83c4 100644
--- a/node/src/bootstrapper.rs
+++ b/node/src/bootstrapper.rs
@@ -400,7 +400,6 @@ impl BootstrapperConfig {
neighborhood_config: NeighborhoodConfig {
mode: NeighborhoodMode::ZeroHop,
min_hops: DEFAULT_MIN_HOPS,
- country: "ZZ".to_string(),
},
when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC,
}
@@ -1156,7 +1155,7 @@ mod tests {
"--real-user",
"123:456:/home/booga",
"--chain",
- "polygon-mumbai",
+ "polygon-amoy",
]))
.unwrap();
@@ -1240,7 +1239,6 @@ mod tests {
let neighborhood_config = NeighborhoodConfig {
mode: NeighborhoodMode::OriginateOnly(vec![], rate_pack(9)),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
let earning_wallet = make_wallet("earning wallet");
let consuming_wallet_opt = Some(make_wallet("consuming wallet"));
@@ -1861,7 +1859,6 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
config.data_directory = data_dir.clone();
config.clandestine_port_opt = Some(port);
@@ -1932,7 +1929,6 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
config.data_directory = data_dir.clone();
config.clandestine_port_opt = None;
@@ -1982,7 +1978,6 @@ mod tests {
rate_pack(100),
),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
let listener_handler = ListenerHandlerNull::new(vec![]);
let mut subject = BootstrapperBuilder::new()
@@ -2020,7 +2015,6 @@ mod tests {
cryptde,
))]),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
let listener_handler = ListenerHandlerNull::new(vec![]);
let mut subject = BootstrapperBuilder::new()
@@ -2051,7 +2045,6 @@ mod tests {
config.neighborhood_config = NeighborhoodConfig {
mode: NeighborhoodMode::ZeroHop,
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
let listener_handler = ListenerHandlerNull::new(vec![]);
let mut subject = BootstrapperBuilder::new()
@@ -2083,7 +2076,6 @@ mod tests {
config.neighborhood_config = NeighborhoodConfig {
mode: NeighborhoodMode::Standard(NodeAddr::default(), vec![], DEFAULT_RATE_PACK),
min_hops: MIN_HOPS_FOR_TEST,
- country: "ZZ".to_string(),
};
let mut subject = BootstrapperBuilder::new().config(config).build();
subject.set_up_clandestine_port();
diff --git a/node/src/daemon/mod.rs b/node/src/daemon/mod.rs
index 78b8491e9..f16bcbc7f 100644
--- a/node/src/daemon/mod.rs
+++ b/node/src/daemon/mod.rs
@@ -161,7 +161,7 @@ impl Daemon {
node_process_id: None,
node_ui_port: None,
verifier_tools: Box::new(VerifierToolsReal::new()),
- setup_reporter: Box::new(SetupReporterReal::new(Box::new(DirsWrapperReal {}))),
+ setup_reporter: Box::new(SetupReporterReal::new(Box::new(DirsWrapperReal::default()))),
logger: Logger::new("Daemon"),
}
}
diff --git a/node/src/daemon/setup_reporter.rs b/node/src/daemon/setup_reporter.rs
index d882ee773..69970c297 100644
--- a/node/src/daemon/setup_reporter.rs
+++ b/node/src/daemon/setup_reporter.rs
@@ -26,7 +26,7 @@ use crate::sub_lib::neighborhood::NodeDescriptor;
use crate::sub_lib::neighborhood::{NeighborhoodMode as NeighborhoodModeEnum, DEFAULT_RATE_PACK};
use crate::sub_lib::utils::make_new_multi_config;
use crate::test_utils::main_cryptde;
-use clap::value_t;
+use clap::{value_t, App};
use itertools::Itertools;
use masq_lib::blockchains::chains::Chain as BlockChain;
use masq_lib::constants::DEFAULT_CHAIN;
@@ -36,8 +36,10 @@ use masq_lib::messages::{UiSetupRequestValue, UiSetupResponseValue, UiSetupRespo
use masq_lib::multi_config::{
CommandLineVcl, ConfigFileVcl, EnvironmentVcl, MultiConfig, VirtualCommandLine,
};
-use masq_lib::shared_schema::{shared_app, ConfiguratorError};
-use masq_lib::utils::{add_chain_specific_directory, to_string, ExpectValue};
+use masq_lib::shared_schema::{data_directory_arg, shared_app, ConfiguratorError};
+use masq_lib::utils::{
+ add_chain_specific_directory, to_string, ExpectValue, DATA_DIRECTORY_DAEMON_HELP,
+};
use std::collections::HashMap;
use std::fmt::Display;
use std::net::{IpAddr, Ipv4Addr};
@@ -67,6 +69,10 @@ pub fn setup_cluster_from(input: Vec<(&str, &str, UiSetupResponseValueStatus)>)
.collect::()
}
+fn daemon_shared_app() -> App<'static, 'static> {
+ shared_app(app_head()).arg(data_directory_arg(DATA_DIRECTORY_DAEMON_HELP.as_str()))
+}
+
pub trait SetupReporter {
fn get_modified_setup(
&self,
@@ -222,7 +228,7 @@ impl SetupReporterReal {
}
pub fn get_default_params() -> SetupCluster {
- let schema = shared_app(app_head());
+ let schema = daemon_shared_app();
schema
.p
.opts
@@ -492,7 +498,7 @@ impl SetupReporterReal {
environment: bool,
config_file: bool,
) -> Result, ConfiguratorError> {
- let app = shared_app(app_head());
+ let app = daemon_shared_app();
let mut vcls: Vec> = vec![];
if let Some(command_line) = command_line_opt.clone() {
vcls.push(Box::new(CommandLineVcl::new(command_line)));
@@ -742,7 +748,7 @@ impl ValueRetriever for DataDirectory {
}
impl std::default::Default for DataDirectory {
fn default() -> Self {
- Self::new(&DirsWrapperReal)
+ Self::new(&DirsWrapperReal::default())
}
}
impl DataDirectory {
@@ -1136,7 +1142,7 @@ impl ValueRetriever for RealUser {
}
impl std::default::Default for RealUser {
fn default() -> Self {
- Self::new(&DirsWrapperReal {})
+ Self::new(&DirsWrapperReal::default())
}
}
impl RealUser {
@@ -1226,9 +1232,8 @@ mod tests {
};
use crate::test_utils::{assert_string_contains, rate_pack};
use core::option::Option;
- use dirs::home_dir;
use masq_lib::blockchains::chains::Chain as Blockchain;
- use masq_lib::blockchains::chains::Chain::PolyMumbai;
+ use masq_lib::blockchains::chains::Chain::PolyAmoy;
use masq_lib::constants::{DEFAULT_CHAIN, DEFAULT_GAS_PRICE};
use masq_lib::messages::UiSetupResponseValueStatus::{Blank, Configured, Required, Set};
use masq_lib::test_utils::environment_guard::{ClapGuard, EnvironmentGuard};
@@ -1239,6 +1244,7 @@ mod tests {
use std::convert::TryFrom;
#[cfg(not(target_os = "windows"))]
use std::default::Default;
+ use std::env::current_dir;
use std::fs::{create_dir_all, File};
use std::io::Write;
use std::net::IpAddr;
@@ -1378,7 +1384,7 @@ mod tests {
.into_iter()
.map(|(name, value)| UiSetupRequestValue::new(name, value))
.collect_vec();
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject
@@ -1436,7 +1442,7 @@ mod tests {
(
"real-user",
&RealUser::new(None, None, None)
- .populate(&DirsWrapperReal {})
+ .populate(&DirsWrapperReal::default())
.to_string(),
Default,
),
@@ -1496,7 +1502,7 @@ mod tests {
("scan-intervals","150|150|150",Set),
("scans", "off", Set),
]);
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject.get_modified_setup(existing_setup, vec![]).unwrap();
@@ -1568,7 +1574,7 @@ mod tests {
].into_iter()
.map (|(name, value)| UiSetupRequestValue::new(name, value))
.collect_vec();
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject
@@ -1643,7 +1649,7 @@ mod tests {
("MASQ_SCAN_INTERVALS","133|133|111")
].into_iter()
.for_each (|(name, value)| std::env::set_var (name, value));
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let params = vec![];
let subject = SetupReporterReal::new(dirs_wrapper);
@@ -1956,7 +1962,7 @@ mod tests {
("scan-intervals", "111|111|111", Set),
("scans", "off", Set),
]);
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject.get_modified_setup(existing_setup, params).unwrap();
@@ -2046,21 +2052,16 @@ mod tests {
}
#[test]
- fn get_modified_setup_tilde_in_config_file_path() {
+ fn get_modified_setup_handles_tilde_in_config_file_and_data_directory_path() {
let _guard = EnvironmentGuard::new();
let base_dir = ensure_node_home_directory_exists(
"setup_reporter",
- "get_modified_setup_tilde_in_data_directory",
+ "get_modified_setup_handles_tilde_in_config_file_and_data_directory_path",
);
let data_dir = base_dir.join("data_dir");
- std::fs::create_dir_all(home_dir().expect("expect home dir").join("masqhome")).unwrap();
- let mut config_file = File::create(
- home_dir()
- .expect("expect home dir")
- .join("masqhome")
- .join("config.toml"),
- )
- .unwrap();
+ std::fs::create_dir_all(base_dir.join("masqhome")).unwrap();
+ let config_file_path = base_dir.join("masqhome").join("config.toml");
+ let mut config_file = File::create(&config_file_path).unwrap();
config_file
.write_all(b"blockchain-service-url = \"https://www.mainnet.com\"\n")
.unwrap();
@@ -2082,12 +2083,11 @@ mod tests {
.collect_vec();
let expected_config_file_data = "https://www.mainnet.com";
- let dirs_wrapper = Box::new(
- DirsWrapperMock::new()
- .data_dir_result(Some(data_dir))
- .home_dir_result(Some(base_dir)),
- );
- let subject = SetupReporterReal::new(dirs_wrapper);
+ let dirs_wrapper = DirsWrapperMock {
+ data_dir_result: Some(PathBuf::from(current_dir().unwrap().join(&data_dir))),
+ home_dir_result: Some(PathBuf::from(current_dir().unwrap().join(&base_dir))),
+ };
+ let subject = SetupReporterReal::new(Box::new(dirs_wrapper));
let result = subject
.get_modified_setup(existing_setup, incoming_setup)
@@ -2264,14 +2264,10 @@ mod tests {
let current_data_dir = base_dir
.join("data_dir")
.join("MASQ")
- .join(BlockChain::PolyMumbai.rec().literal_identifier); //not a default
+ .join(BlockChain::PolyAmoy.rec().literal_identifier); //not a default
let existing_setup = setup_cluster_from(vec![
("blockchain-service-url", "", Required),
- (
- "chain",
- BlockChain::PolyMumbai.rec().literal_identifier,
- Set,
- ),
+ ("chain", BlockChain::PolyAmoy.rec().literal_identifier, Set),
("clandestine-port", "7788", Default),
("config-file", "config.toml", Default),
("consuming-private-key", "", Blank),
@@ -2310,7 +2306,7 @@ mod tests {
.get_modified_setup(existing_setup, incoming_setup)
.unwrap_err();
- let expected_chain = PolyMumbai.rec().literal_identifier;
+ let expected_chain = PolyAmoy.rec().literal_identifier;
let actual_chain = &resulting_setup_cluster.get("chain").unwrap().value;
assert_eq!(actual_chain, expected_chain);
let actual_data_directory =
@@ -2338,7 +2334,7 @@ mod tests {
(
"real-user",
&crate::bootstrapper::RealUser::new(None, None, None)
- .populate(&DirsWrapperReal {})
+ .populate(&DirsWrapperReal::default())
.to_string(),
Default,
),
@@ -2347,7 +2343,7 @@ mod tests {
.into_iter()
.map(|(name, value)| UiSetupRequestValue::new(name, value))
.collect_vec();
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let _ = subject
@@ -2375,7 +2371,7 @@ mod tests {
),
]);
let incoming_setup = vec![UiSetupRequestValue::clear("neighbors")];
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject
@@ -2487,7 +2483,7 @@ mod tests {
let setup = setup_cluster_from(vec![]);
let (real_user_opt, data_directory_opt, chain) =
- SetupReporterReal::calculate_fundamentals(&DirsWrapperReal {}, &setup).unwrap();
+ SetupReporterReal::calculate_fundamentals(&DirsWrapperReal::default(), &setup).unwrap();
assert_eq!(
real_user_opt,
@@ -2518,7 +2514,7 @@ mod tests {
]);
let (real_user_opt, data_directory_opt, chain) =
- SetupReporterReal::calculate_fundamentals(&DirsWrapperReal {}, &setup).unwrap();
+ SetupReporterReal::calculate_fundamentals(&DirsWrapperReal::default(), &setup).unwrap();
assert_eq!(
real_user_opt,
@@ -2549,7 +2545,7 @@ mod tests {
]);
let (real_user_opt, data_directory_opt, chain) =
- SetupReporterReal::calculate_fundamentals(&DirsWrapperReal {}, &setup).unwrap();
+ SetupReporterReal::calculate_fundamentals(&DirsWrapperReal::default(), &setup).unwrap();
assert_eq!(
real_user_opt,
@@ -2576,7 +2572,7 @@ mod tests {
]);
let (real_user_opt, data_directory_opt, chain) =
- SetupReporterReal::calculate_fundamentals(&DirsWrapperReal {}, &setup).unwrap();
+ SetupReporterReal::calculate_fundamentals(&DirsWrapperReal::default(), &setup).unwrap();
assert_eq!(
real_user_opt,
@@ -2599,12 +2595,13 @@ mod tests {
let setup = setup_cluster_from(vec![]);
let (real_user_opt, data_directory_opt, chain) =
- SetupReporterReal::calculate_fundamentals(&DirsWrapperReal {}, &setup).unwrap();
+ SetupReporterReal::calculate_fundamentals(&DirsWrapperReal::default(), &setup).unwrap();
assert_eq!(
real_user_opt,
Some(
- crate::bootstrapper::RealUser::new(None, None, None).populate(&DirsWrapperReal {})
+ crate::bootstrapper::RealUser::new(None, None, None)
+ .populate(&DirsWrapperReal::default())
)
);
assert_eq!(data_directory_opt, None);
@@ -2618,7 +2615,7 @@ mod tests {
"setup_reporter",
"blanking_a_parameter_with_a_default_produces_that_default",
);
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject
@@ -2690,7 +2687,7 @@ mod tests {
.into_iter()
.map(|uisrv| (uisrv.name.clone(), uisrv))
.collect();
- let subject = SetupReporterReal::new(Box::new(DirsWrapperReal {}));
+ let subject = SetupReporterReal::new(Box::new(DirsWrapperReal::default()));
let result = subject
.calculate_configured_setup(&setup, &data_directory)
@@ -2712,6 +2709,7 @@ mod tests {
#[test]
fn config_file_not_specified_but_exists() {
+ let _guard = EnvironmentGuard::new();
let data_directory = ensure_node_home_directory_exists(
"setup_reporter",
"config_file_not_specified_but_exists",
@@ -2736,7 +2734,7 @@ mod tests {
.map(|uisrv| (uisrv.name.clone(), uisrv))
.collect();
- let (result, _) = SetupReporterReal::new(Box::new(DirsWrapperReal {}))
+ let (result, _) = SetupReporterReal::new(Box::new(DirsWrapperReal::default()))
.calculate_configured_setup(&setup, &*data_directory);
assert_eq!(result.get("gas-price").unwrap().value, "10".to_string());
@@ -2744,6 +2742,7 @@ mod tests {
#[test]
fn config_file_has_relative_directory_that_exists_in_data_directory() {
+ let _guard = EnvironmentGuard::new();
let data_directory = ensure_node_home_directory_exists(
"setup_reporter",
"config_file_has_relative_directory_that_exists_in_data_directory",
@@ -2757,7 +2756,7 @@ mod tests {
}
let setup = vec![
//no config-file setting
- UiSetupResponseValue::new("chain", "polygon-mumbai", Set),
+ UiSetupResponseValue::new("chain", "polygon-amoy", Set),
UiSetupResponseValue::new("neighborhood-mode", "zero-hop", Set),
UiSetupResponseValue::new("config-file", "booga/special.toml", Set),
UiSetupResponseValue::new(
@@ -2769,7 +2768,7 @@ mod tests {
.into_iter()
.map(|uisrv| (uisrv.name.clone(), uisrv))
.collect();
- let subject = SetupReporterReal::new(Box::new(DirsWrapperReal {}));
+ let subject = SetupReporterReal::new(Box::new(DirsWrapperReal::default()));
let result = subject
.calculate_configured_setup(&setup, &data_directory)
.0;
@@ -2795,7 +2794,7 @@ mod tests {
.into_iter()
.map(|uisrv| (uisrv.name.clone(), uisrv))
.collect();
- let subject = SetupReporterReal::new(Box::new(DirsWrapperReal {}));
+ let subject = SetupReporterReal::new(Box::new(DirsWrapperReal::default()));
let result = subject
.calculate_configured_setup(&setup, &data_directory)
@@ -2833,7 +2832,7 @@ mod tests {
.into_iter()
.map(|uisrv| (uisrv.name.clone(), uisrv))
.collect();
- let subject = SetupReporterReal::new(Box::new(DirsWrapperReal {}));
+ let subject = SetupReporterReal::new(Box::new(DirsWrapperReal::default()));
let result = subject.calculate_configured_setup(&setup, &data_dir).0;
@@ -2848,7 +2847,7 @@ mod tests {
);
let config_file_dir = config_file_dir.canonicalize().unwrap();
let config_file_path = config_file_dir.join("nonexistent.toml");
- let wrapper = DirsWrapperReal {};
+ let wrapper = DirsWrapperReal::default();
let data_directory = wrapper
.data_dir()
.unwrap()
@@ -2866,7 +2865,7 @@ mod tests {
.into_iter()
.map(|uisrv| (uisrv.name.clone(), uisrv))
.collect();
- let subject = SetupReporterReal::new(Box::new(DirsWrapperReal {}));
+ let subject = SetupReporterReal::new(Box::new(DirsWrapperReal::default()));
let result = subject
.calculate_configured_setup(&setup, &data_directory)
@@ -2919,11 +2918,14 @@ mod tests {
#[test]
fn data_directory_computed_default() {
- let real_user = RealUser::new(None, None, None).populate(&DirsWrapperReal {});
- let expected =
- data_directory_from_context(&DirsWrapperReal {}, &real_user, Blockchain::EthMainnet)
- .to_string_lossy()
- .to_string();
+ let real_user = RealUser::new(None, None, None).populate(&DirsWrapperReal::default());
+ let expected = data_directory_from_context(
+ &DirsWrapperReal::default(),
+ &real_user,
+ Blockchain::EthMainnet,
+ )
+ .to_string_lossy()
+ .to_string();
let mut config = BootstrapperConfig::new();
config.real_user = real_user;
config.blockchain_bridge_config.chain = Blockchain::from("eth-mainnet");
@@ -3317,7 +3319,7 @@ mod tests {
result,
Some((
RealUser::new(None, None, None)
- .populate(&DirsWrapperReal {})
+ .populate(&DirsWrapperReal::default())
.to_string(),
Default
))
@@ -3699,7 +3701,7 @@ mod tests {
"data-directory",
&masqhome.to_str().unwrap(),
)];
- let dirs_wrapper = Box::new(DirsWrapperReal);
+ let dirs_wrapper = Box::new(DirsWrapperReal::default());
let subject = SetupReporterReal::new(dirs_wrapper);
let result = subject.get_modified_setup(existing_setup, incoming_setup);
@@ -3716,10 +3718,10 @@ mod tests {
let _guard = EnvironmentGuard::new();
let existing_setup =
setup_cluster_from(vec![("real-user", "1111:1111:/home/booga", Default)]);
- let incoming_setup = vec![UiSetupRequestValue::new("chain", "polygon-mumbai")];
+ let incoming_setup = vec![UiSetupRequestValue::new("chain", "polygon-amoy")];
let home_directory = Path::new("/home/booga");
let data_directory = home_directory.join("data");
- let expected = data_directory.join("MASQ").join("polygon-mumbai");
+ let expected = data_directory.join("MASQ").join("polygon-amoy");
let dirs_wrapper = Box::new(
DirsWrapperMock::new()
.data_dir_result(Some(data_directory))
diff --git a/node/src/database/config_dumper.rs b/node/src/database/config_dumper.rs
index 891eac1ad..17e24899e 100644
--- a/node/src/database/config_dumper.rs
+++ b/node/src/database/config_dumper.rs
@@ -198,7 +198,7 @@ mod tests {
.opt("--dump-config")
.into();
let subject = DumpConfigRunnerReal {
- dirs_wrapper: Box::new(DirsWrapperReal),
+ dirs_wrapper: Box::new(DirsWrapperReal::default()),
};
let caught_panic = catch_unwind(AssertUnwindSafe(|| {
@@ -239,7 +239,7 @@ mod tests {
.opt("--dump-config")
.into();
let subject = DumpConfigRunnerReal {
- dirs_wrapper: Box::new(DirsWrapperReal),
+ dirs_wrapper: Box::new(DirsWrapperReal::default()),
};
let result = subject.go(&mut holder.streams(), args_vec.as_slice());
@@ -353,11 +353,7 @@ mod tests {
);
assert_value("neighborhoodMode", "zero-hop", &map);
assert_value("schemaVersion", &CURRENT_SCHEMA_VERSION.to_string(), &map);
- assert_value(
- "startBlock",
- &Chain::PolyMainnet.rec().contract_creation_block.to_string(),
- &map,
- );
+ assert_null("startBlock", &map);
assert_value(
"exampleEncrypted",
&dao.get("example_encrypted").unwrap().value_opt.unwrap(),
@@ -471,7 +467,7 @@ mod tests {
.opt("--dump-config")
.into();
let subject = DumpConfigRunnerReal {
- dirs_wrapper: Box::new(DirsWrapperReal),
+ dirs_wrapper: Box::new(DirsWrapperReal::default()),
};
let result = subject.go(&mut holder.streams(), args_vec.as_slice());
@@ -503,11 +499,7 @@ mod tests {
assert_value("pastNeighbors", "masq://polygon-mainnet:QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU@1.2.3.4:1234,masq://polygon-mainnet:QkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY@2.3.4.5:2345", &map);
assert_value("neighborhoodMode", "consume-only", &map);
assert_value("schemaVersion", &CURRENT_SCHEMA_VERSION.to_string(), &map);
- assert_value(
- "startBlock",
- &Chain::PolyMainnet.rec().contract_creation_block.to_string(),
- &map,
- );
+ assert_null("startBlock", &map);
let expected_ee_entry = dao.get("example_encrypted").unwrap().value_opt.unwrap();
let expected_ee_decrypted = Bip39::decrypt_bytes(&expected_ee_entry, "password").unwrap();
let expected_ee_string = encode_bytes(Some(expected_ee_decrypted)).unwrap().unwrap();
@@ -579,7 +571,7 @@ mod tests {
.opt("--dump-config")
.into();
let subject = DumpConfigRunnerReal {
- dirs_wrapper: Box::new(DirsWrapperReal),
+ dirs_wrapper: Box::new(DirsWrapperReal::default()),
};
let result = subject.go(&mut holder.streams(), args_vec.as_slice());
@@ -620,11 +612,7 @@ mod tests {
);
assert_value("neighborhoodMode", "standard", &map);
assert_value("schemaVersion", &CURRENT_SCHEMA_VERSION.to_string(), &map);
- assert_value(
- "startBlock",
- &Chain::PolyMainnet.rec().contract_creation_block.to_string(),
- &map,
- );
+ assert_null("startBlock", &map);
assert_value(
"exampleEncrypted",
&dao.get("example_encrypted").unwrap().value_opt.unwrap(),
@@ -679,6 +667,18 @@ mod tests {
assert_eq!(actual_value, expected_value);
}
+ fn assert_null(key: &str, map: &Map) {
+ assert!(map.contains_key(key));
+ let value = map
+ .get(key)
+ .unwrap_or_else(|| panic!("record for {} is missing", key));
+ assert!(
+ value.is_null(),
+ "Expecting {} to be null, but it wasn't",
+ value
+ )
+ }
+
fn assert_encrypted_value(
key: &str,
expected_value: &str,
diff --git a/node/src/database/db_initializer.rs b/node/src/database/db_initializer.rs
index 8bfb9c1eb..3619cc1b4 100644
--- a/node/src/database/db_initializer.rs
+++ b/node/src/database/db_initializer.rs
@@ -205,13 +205,7 @@ impl DbInitializerReal {
Self::set_config_value(
conn,
"start_block",
- Some(
- &external_params
- .chain
- .rec()
- .contract_creation_block
- .to_string(),
- ),
+ None,
false,
&format!(
"{} start block",
@@ -658,7 +652,7 @@ mod tests {
#[test]
fn constants_have_correct_values() {
assert_eq!(DATABASE_FILE, "node-data.db");
- assert_eq!(CURRENT_SCHEMA_VERSION, 9);
+ assert_eq!(CURRENT_SCHEMA_VERSION, 10);
}
#[test]
@@ -967,15 +961,7 @@ mod tests {
Some(&CURRENT_SCHEMA_VERSION.to_string()),
false,
);
- verify(
- &mut config_vec,
- "start_block",
- Some(&format!(
- "{}",
- &TEST_DEFAULT_CHAIN.rec().contract_creation_block.to_string()
- )),
- false,
- );
+ verify(&mut config_vec, "start_block", None, false);
assert_eq!(config_vec, vec![]);
}
diff --git a/node/src/database/db_migrations/db_migrator.rs b/node/src/database/db_migrations/db_migrator.rs
index 746af3e26..7d1ec4f8c 100644
--- a/node/src/database/db_migrations/db_migrator.rs
+++ b/node/src/database/db_migrations/db_migrator.rs
@@ -10,6 +10,7 @@ use crate::database::db_migrations::migrations::migration_5_to_6::Migrate_5_to_6
use crate::database::db_migrations::migrations::migration_6_to_7::Migrate_6_to_7;
use crate::database::db_migrations::migrations::migration_7_to_8::Migrate_7_to_8;
use crate::database::db_migrations::migrations::migration_8_to_9::Migrate_8_to_9;
+use crate::database::db_migrations::migrations::migration_9_to_10::Migrate_9_to_10;
use crate::database::db_migrations::migrator_utils::{
DBMigDeclarator, DBMigrationUtilities, DBMigrationUtilitiesReal, DBMigratorInnerConfiguration,
};
@@ -78,6 +79,7 @@ impl DbMigratorReal {
&Migrate_6_to_7,
&Migrate_7_to_8,
&Migrate_8_to_9,
+ &Migrate_9_to_10,
]
}
diff --git a/node/src/database/db_migrations/migrations/migration_8_to_9.rs b/node/src/database/db_migrations/migrations/migration_8_to_9.rs
index c5928edb6..4bf95e955 100644
--- a/node/src/database/db_migrations/migrations/migration_8_to_9.rs
+++ b/node/src/database/db_migrations/migrations/migration_8_to_9.rs
@@ -43,27 +43,28 @@ mod tests {
let _ = bring_db_0_back_to_life_and_return_connection(&db_path);
let subject = DbInitializerReal::default();
+ let result = subject.initialize_to_version(
+ &dir_path,
+ 8,
+ DbInitializationConfig::create_or_migrate(make_external_data()),
+ );
+
+ assert!(result.is_ok());
+
let result = subject.initialize_to_version(
&dir_path,
9,
DbInitializationConfig::create_or_migrate(make_external_data()),
);
+
let connection = result.unwrap();
let (mp_value, mp_encrypted) = retrieve_config_row(connection.as_ref(), "max_block_count");
let (cs_value, cs_encrypted) = retrieve_config_row(connection.as_ref(), "schema_version");
assert_eq!(mp_value, None);
assert_eq!(mp_encrypted, false);
- assert_eq!(cs_value, Some("9".to_string()));
+ assert_eq!(cs_value, Some(9.to_string()));
assert_eq!(cs_encrypted, false);
TestLogHandler::new().assert_logs_contain_in_order(vec![
- "DbMigrator: Database successfully migrated from version 0 to 1",
- "DbMigrator: Database successfully migrated from version 1 to 2",
- "DbMigrator: Database successfully migrated from version 2 to 3",
- "DbMigrator: Database successfully migrated from version 3 to 4",
- "DbMigrator: Database successfully migrated from version 4 to 5",
- "DbMigrator: Database successfully migrated from version 5 to 6",
- "DbMigrator: Database successfully migrated from version 6 to 7",
- "DbMigrator: Database successfully migrated from version 7 to 8",
"DbMigrator: Database successfully migrated from version 8 to 9",
]);
}
diff --git a/node/src/database/db_migrations/migrations/migration_9_to_10.rs b/node/src/database/db_migrations/migrations/migration_9_to_10.rs
new file mode 100644
index 000000000..7622ef01f
--- /dev/null
+++ b/node/src/database/db_migrations/migrations/migration_9_to_10.rs
@@ -0,0 +1,71 @@
+use crate::database::db_migrations::db_migrator::DatabaseMigration;
+use crate::database::db_migrations::migrator_utils::DBMigDeclarator;
+
+#[allow(non_camel_case_types)]
+pub struct Migrate_9_to_10;
+
+impl DatabaseMigration for Migrate_9_to_10 {
+ fn migrate<'a>(
+ &self,
+ declaration_utils: Box,
+ ) -> rusqlite::Result<()> {
+ declaration_utils.execute_upon_transaction(&[
+ &"INSERT INTO config (name, value, encrypted) VALUES ('max_block_count', 100000, 0) ON CONFLICT(name) DO UPDATE SET value = 100000 WHERE name = 'max_block_count'"
+ ])
+ }
+
+ fn old_version(&self) -> usize {
+ 9
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::database::db_initializer::{
+ DbInitializationConfig, DbInitializer, DbInitializerReal, DATABASE_FILE,
+ };
+ use crate::test_utils::database_utils::{
+ bring_db_0_back_to_life_and_return_connection, make_external_data, retrieve_config_row,
+ };
+ use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler};
+ use masq_lib::test_utils::utils::ensure_node_home_directory_exists;
+ use std::fs::create_dir_all;
+
+ #[test]
+ fn migration_from_9_to_10_is_properly_set() {
+ init_test_logging();
+ let dir_path = ensure_node_home_directory_exists(
+ "db_migrations",
+ "migration_from_9_to_10_is_properly_set",
+ );
+ create_dir_all(&dir_path).unwrap();
+ let db_path = dir_path.join(DATABASE_FILE);
+ let _ = bring_db_0_back_to_life_and_return_connection(&db_path);
+ let subject = DbInitializerReal::default();
+
+ let result = subject.initialize_to_version(
+ &dir_path,
+ 9,
+ DbInitializationConfig::create_or_migrate(make_external_data()),
+ );
+
+ assert!(result.is_ok());
+
+ let result = subject.initialize_to_version(
+ &dir_path,
+ 10,
+ DbInitializationConfig::create_or_migrate(make_external_data()),
+ );
+
+ let connection = result.unwrap();
+ let (mp_value, mp_encrypted) = retrieve_config_row(connection.as_ref(), "max_block_count");
+ let (cs_value, cs_encrypted) = retrieve_config_row(connection.as_ref(), "schema_version");
+ assert_eq!(mp_value, Some(100_000u64.to_string()));
+ assert_eq!(mp_encrypted, false);
+ assert_eq!(cs_value, Some(10.to_string()));
+ assert_eq!(cs_encrypted, false);
+ TestLogHandler::new().assert_logs_contain_in_order(vec![
+ "DbMigrator: Database successfully migrated from version 9 to 10",
+ ]);
+ }
+}
diff --git a/node/src/database/db_migrations/migrations/mod.rs b/node/src/database/db_migrations/migrations/mod.rs
index 68b10ca9b..bcdb14176 100644
--- a/node/src/database/db_migrations/migrations/mod.rs
+++ b/node/src/database/db_migrations/migrations/mod.rs
@@ -9,3 +9,4 @@ pub mod migration_5_to_6;
pub mod migration_6_to_7;
pub mod migration_7_to_8;
pub mod migration_8_to_9;
+pub mod migration_9_to_10;
diff --git a/node/src/db_config/config_dao.rs b/node/src/db_config/config_dao.rs
index 23bd1fce5..36798dd05 100644
--- a/node/src/db_config/config_dao.rs
+++ b/node/src/db_config/config_dao.rs
@@ -180,7 +180,7 @@ mod tests {
use crate::database::db_initializer::{DbInitializer, DbInitializerReal};
use crate::database::test_utils::ConnectionWrapperMock;
use crate::test_utils::assert_contains;
- use masq_lib::constants::{CURRENT_SCHEMA_VERSION, ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK};
+ use masq_lib::constants::CURRENT_SCHEMA_VERSION;
use masq_lib::test_utils::utils::ensure_node_home_directory_exists;
use rusqlite::Connection;
use std::path::Path;
@@ -201,14 +201,7 @@ mod tests {
false,
),
);
- assert_contains(
- &result,
- &ConfigDaoRecord::new(
- "start_block",
- Some(&ROPSTEN_TESTNET_CONTRACT_CREATION_BLOCK.to_string()),
- false,
- ),
- );
+ assert_contains(&result, &ConfigDaoRecord::new("start_block", None, false));
assert_contains(
&result,
&ConfigDaoRecord::new("consuming_wallet_private_key", None, true),
diff --git a/node/src/db_config/persistent_configuration.rs b/node/src/db_config/persistent_configuration.rs
index da3fa1583..532048a34 100644
--- a/node/src/db_config/persistent_configuration.rs
+++ b/node/src/db_config/persistent_configuration.rs
@@ -113,7 +113,7 @@ pub trait PersistentConfiguration {
fn mapping_protocol(&self) -> Result