Repository: mintlayer/mintlayer-core (rust)

Issue:
No sync progress when opening a wallet in node-gui
If you open a wallet that requires syncing, the UI will stay in the original state without any visual clues of what's happening until the syncing is done, which is very confusing.
E.g. I have a wallet that was last synced 5 months ago, and the delay is over a minute in this case.

P.S. we had a similar problem when recovering a wallet, which is now fixed.

Pull request:
Don't wait for wallet syncing when opening in GUI
We no longer wait for the wallet to sync with the blokchain if opened through the GUI or RPC.

Closes #1877 

Patch:
diff --git a/build-tools/docker/Dockerfile.builder b/build-tools/docker/Dockerfile.builder
index 1cffd0eb7..20c737c28 100644
--- a/build-tools/docker/Dockerfile.builder
+++ b/build-tools/docker/Dockerfile.builder
@@ -16,6 +16,7 @@ FROM rust AS builder
 
 WORKDIR /usr/src/
 
+# Install necessary build dependencies for the GUI (such as X11, etc.)
 RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
 
 COPY --from=source /src/ /usr/src/
diff --git a/build-tools/docker/build.py b/build-tools/docker/build.py
index 4f17feb1a..e12804fad 100644
--- a/build-tools/docker/build.py
+++ b/build-tools/docker/build.py
@@ -20,20 +20,11 @@ def get_cargo_version(cargo_toml_path):
     return version
 
 
-def build_docker_image(dockerfile_path, image_name, tags, num_jobs=None):
+def build_docker_image(dockerfile_path, image_name, version, num_jobs=None):
     # Docker build command
-    command = f"docker build"
-
-    full_tags = [image_name] if len(tags) == 0 else [f"{image_name}:{tag}" for tag in tags];
-
-    for full_tag in full_tags:
-        command += f" -t {full_tag}"
-
-    command += f" -f {dockerfile_path}"
-
+    command = f"docker build -t {image_name}:{version} -f {dockerfile_path}"
     if num_jobs:
         command += f" --build-arg NUM_JOBS={num_jobs}"
-
     # Note: "plain" output is more verbose, but it makes it easier to understand what went wrong
     # when a problem occurs.
     command += " --progress=plain"
@@ -42,7 +33,7 @@ def build_docker_image(dockerfile_path, image_name, tags, num_jobs=None):
     try:
         # Run the command
         subprocess.check_call(command, shell=True)
-        print(f"Built {image_name} successfully (the tags are: {full_tags}).")
+        print(f"Built {image_name}:{version} successfully.")
     except Exception as error:
         print(f"Error occurred: {error}")
         exit(1) # stop the build
@@ -85,24 +76,26 @@ def delete_docker_image(image_name, version):
         print(f"Failed to delete {full_image_name}.")
 
 
-def build_instances(tags, docker_hub_user, num_jobs):
+def build_instances(version, docker_hub_user, num_jobs):
+    if num_jobs is None:
+        num_jobs = os.cpu_count() or 1
+
     build_docker_image("build-tools/docker/Dockerfile.builder",
-                        "mintlayer-builder", ["latest"], num_jobs)
+                        "mintlayer-builder", "latest", num_jobs)
     build_docker_image("build-tools/docker/Dockerfile.runner-base",
-                        "mintlayer-runner-base", ["latest"], num_jobs)
-
+                        "mintlayer-runner-base", "latest", num_jobs)
     build_docker_image("build-tools/docker/Dockerfile.node-daemon",
-                        f"{docker_hub_user}/node-daemon", tags)
+                        f"{docker_hub_user}/node-daemon", version)
     build_docker_image("build-tools/docker/Dockerfile.api-blockchain-scanner-daemon",
-                        f"{docker_hub_user}/api-blockchain-scanner-daemon", tags)
+                        f"{docker_hub_user}/api-blockchain-scanner-daemon", version)
     build_docker_image("build-tools/docker/Dockerfile.api-web-server",
-                        f"{docker_hub_user}/api-web-server", tags)
+                        f"{docker_hub_user}/api-web-server", version)
     build_docker_image("build-tools/docker/Dockerfile.wallet-cli",
-                        f"{docker_hub_user}/wallet-cli", tags)
+                        f"{docker_hub_user}/wallet-cli", version)
     build_docker_image("build-tools/docker/Dockerfile.wallet-rpc-daemon",
-                        f"{docker_hub_user}/wallet-rpc-daemon", tags)
+                        f"{docker_hub_user}/wallet-rpc-daemon", version)
     build_docker_image("build-tools/docker/Dockerfile.dns-server",
-                        f"{docker_hub_user}/dns-server", tags)
+                        f"{docker_hub_user}/dns-server", version)
 #    delete_docker_image("mintlayer-builder", "latest")
 
 
@@ -116,25 +109,24 @@ def push_instances(docker_hub_user, version, latest):
 
 
 def main():
-    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser = argparse.ArgumentParser()
     parser.add_argument('--push', action='store_true', help='Push the Docker image to Docker Hub')
     parser.add_argument('--docker-hub-user', help='Docker Hub username', default='mintlayer')
     parser.add_argument('--latest', action='store_true', help='Tag the Docker image as latest while pushing')
     parser.add_argument('--build', type=lambda x: (str(x).lower() == 'true'), default=True, help="Set to false avoid the build")
     parser.add_argument('--version', help='Override version number', default=None)
-    parser.add_argument('--num_jobs', help='Number of parallel jobs', default=(os.cpu_count() or 1))
-    parser.add_argument('--local_tags', nargs='*', help='Additional tags to apply (these won\'t be pushed)', default=[])
+    parser.add_argument('--num_jobs', help='Number of parallel jobs, defaults to # of CPUs', default=None)
     args = parser.parse_args()
 
     version = args.version if args.version else get_cargo_version("Cargo.toml")
-    tags = [version, *args.local_tags]
 
     if args.build:
-        build_instances(tags, args.docker_hub_user, args.num_jobs)
+        build_instances(version, args.docker_hub_user, args.num_jobs)
 
     # Only push the image if the --push flag is provided
     if args.push:
-        push_instances(args.docker_hub_user, version, args.latest)
+        latest = args.latest
+        push_instances(args.docker_hub_user, version, latest)
 
 
 if __name__ == "__main__":
diff --git a/build-tools/docker/example-mainnet-dns-server/.env b/build-tools/docker/example-mainnet-dns-server/.env
index b0028bbb4..58f872dba 100644
--- a/build-tools/docker/example-mainnet-dns-server/.env
+++ b/build-tools/docker/example-mainnet-dns-server/.env
@@ -3,9 +3,9 @@
 COMPOSE_PROJECT_NAME=mintlayer-mainnet-dns-server
 
 # Dockerhub username, from which the docker images will be pulled.
-ML_DOCKERHUB_USERNAME=mintlayer
+DOCKERHUB_USERNAME=mintlayer
 # The image tag to use, e.g. "v1.0.2" or "latest".
-ML_DOCKER_IMAGE_TAG=latest
+IMAGE_TAG=latest
 
 # The user and group ids that will be used to run the software.
 ML_USER_ID=10001
diff --git a/build-tools/docker/example-mainnet-dns-server/docker-compose.yml b/build-tools/docker/example-mainnet-dns-server/docker-compose.yml
index a75d73f4c..f7c79b7ba 100644
--- a/build-tools/docker/example-mainnet-dns-server/docker-compose.yml
+++ b/build-tools/docker/example-mainnet-dns-server/docker-compose.yml
@@ -1,6 +1,6 @@
 services:
   dns-server:
-    image: $ML_DOCKERHUB_USERNAME/dns-server:$ML_DOCKER_IMAGE_TAG
+    image: $DOCKERHUB_USERNAME/dns-server:$IMAGE_TAG
     volumes:
       - ./mintlayer-data:/home/mintlayer
     command: dns-server
diff --git a/build-tools/docker/example-mainnet/.env b/build-tools/docker/example-mainnet/.env
index b45c3635f..81fc53598 100644
--- a/build-tools/docker/example-mainnet/.env
+++ b/build-tools/docker/example-mainnet/.env
@@ -3,9 +3,9 @@
 COMPOSE_PROJECT_NAME=mintlayer-mainnet
 
 # Dockerhub username, from which the docker images will be pulled.
-ML_DOCKERHUB_USERNAME=mintlayer
+DOCKERHUB_USERNAME=mintlayer
 # The image tag to use, e.g. "v1.0.2" or "latest".
-ML_DOCKER_IMAGE_TAG=latest
+IMAGE_TAG=latest
 
 # The user and group ids that will be used to run the software.
 ML_USER_ID=10001
@@ -19,8 +19,6 @@ API_SERVER_POSTGRES_USER=postgres
 API_SERVER_POSTGRES_DB=postgres
 # The password for the postgres dbms.
 API_SERVER_POSTGRES_PASSWORD=use-strong-password
-# The docker image tag to use.
-API_SERVER_POSTGRES_DOCKER_IMAGE_TAG=17.2
 
 # The node's rpc port will be mapped to this port on the host machine.
 # Note that it will only be reachable from localhost and not from other network interfaces.
diff --git a/build-tools/docker/example-mainnet/docker-compose.yml b/build-tools/docker/example-mainnet/docker-compose.yml
index ccce4bc9e..c464fefc6 100644
--- a/build-tools/docker/example-mainnet/docker-compose.yml
+++ b/build-tools/docker/example-mainnet/docker-compose.yml
@@ -10,7 +10,7 @@ x-common-env: &ml-common-env
 services:
   node-daemon:
     <<: *ml-common
-    image: $ML_DOCKERHUB_USERNAME/node-daemon:$ML_DOCKER_IMAGE_TAG
+    image: $DOCKERHUB_USERNAME/node-daemon:$IMAGE_TAG
     command: node-daemon mainnet
     environment:
       <<: *ml-common-env
@@ -41,7 +41,7 @@ services:
 
   ### Services needed to run the api server ###
   api-postgres-db:
-    image: postgres:$API_SERVER_POSTGRES_DOCKER_IMAGE_TAG
+    image: postgres
     restart: always
     environment:
       POSTGRES_USER: $API_SERVER_POSTGRES_USER
@@ -58,7 +58,7 @@ services:
 
   api-blockchain-scanner-daemon:
     <<: *ml-common
-    image: $ML_DOCKERHUB_USERNAME/api-blockchain-scanner-daemon:$ML_DOCKER_IMAGE_TAG
+    image: $DOCKERHUB_USERNAME/api-blockchain-scanner-daemon:$IMAGE_TAG
     command: api-blockchain-scanner-daemon
     depends_on:
       - api-postgres-db
@@ -75,7 +75,7 @@ services:
 
   api-web-server:
     <<: *ml-common
-    image: $ML_DOCKERHUB_USERNAME/api-web-server:$ML_DOCKER_IMAGE_TAG
+    image: $DOCKERHUB_USERNAME/api-web-server:$IMAGE_TAG
     command: api-web-server
     depends_on:
       - api-postgres-db
@@ -97,7 +97,7 @@ services:
 
   wallet-rpc-daemon:
     <<: *ml-common
-    image: $ML_DOCKERHUB_USERNAME/wallet-rpc-daemon:$ML_DOCKER_IMAGE_TAG
+    image: $DOCKERHUB_USERNAME/wallet-rpc-daemon:$IMAGE_TAG
     command: wallet-rpc-daemon mainnet
     depends_on:
       - node-daemon
@@ -118,7 +118,7 @@ services:
   # to run it via "docker compose run"
   wallet-cli:
     <<: *ml-common
-    image: $ML_DOCKERHUB_USERNAME/wallet-cli:$ML_DOCKER_IMAGE_TAG
+    image: $DOCKERHUB_USERNAME/wallet-cli:$IMAGE_TAG
     command: wallet-cli
     depends_on:
       - node-daemon
diff --git a/node-gui/backend/src/backend_impl.rs b/node-gui/backend/src/backend_impl.rs
index 459250536..9ecb77e9d 100644
--- a/node-gui/backend/src/backend_impl.rs
+++ b/node-gui/backend/src/backend_impl.rs
@@ -42,7 +42,8 @@ use wallet_controller::{
 use wallet_rpc_client::handles_client::WalletRpcHandlesClient;
 use wallet_rpc_lib::{EventStream, WalletRpc, WalletService};
 use wallet_types::{
-    seed_phrase::StoreSeedPhrase, wallet_type::WalletType, with_locked::WithLocked,
+    scan_blockchain::ScanBlockchain, seed_phrase::StoreSeedPhrase, wallet_type::WalletType,
+    with_locked::WithLocked,
 };
 
 use super::{
@@ -527,7 +528,7 @@ impl Backend {
         let chain_config = wallet_service.chain_config().clone();
         let wallet_rpc = WalletRpc::new(wallet_handle, node_rpc.clone(), chain_config.clone());
         wallet_rpc
-            .open_wallet(file_path, None, false)
+            .open_wallet(file_path, None, false, ScanBlockchain::ScanNoWait)
             .await
             .map_err(|err| BackendError::WalletError(err.to_string()))?;
         tokio::spawn(forward_events(
diff --git a/wallet/wallet-rpc-client/src/handles_client/mod.rs b/wallet/wallet-rpc-client/src/handles_client/mod.rs
index 17a0baa16..a82182002 100644
--- a/wallet/wallet-rpc-client/src/handles_client/mod.rs
+++ b/wallet/wallet-rpc-client/src/handles_client/mod.rs
@@ -146,7 +146,12 @@ impl<N: NodeInterface + Clone + Send + Sync + Debug + 'static> WalletInterface
         force_migrate_wallet_type: Option<bool>,
     ) -> Result<(), Self::Error> {
         self.wallet_rpc
-            .open_wallet(path, password, force_migrate_wallet_type.unwrap_or(false))
+            .open_wallet(
+                path,
+                password,
+                force_migrate_wallet_type.unwrap_or(false),
+                ScanBlockchain::ScanAndWait,
+            )
             .await
             .map_err(WalletRpcHandlesClientError::WalletRpcError)
     }
diff --git a/wallet/wallet-rpc-lib/src/rpc/mod.rs b/wallet/wallet-rpc-lib/src/rpc/mod.rs
index 2acb52489..3835159f9 100644
--- a/wallet/wallet-rpc-lib/src/rpc/mod.rs
+++ b/wallet/wallet-rpc-lib/src/rpc/mod.rs
@@ -154,13 +154,19 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static> WalletRpc<N> {
         wallet_path: PathBuf,
         password: Option<String>,
         force_migrate_wallet_type: bool,
+        scan_blockchain: ScanBlockchain,
     ) -> WRpcResult<(), N> {
         Ok(self
             .wallet
             .manage_async(move |wallet_manager| {
                 Box::pin(async move {
                     wallet_manager
-                        .open_wallet(wallet_path, password, force_migrate_wallet_type)
+                        .open_wallet(
+                            wallet_path,
+                            password,
+                            force_migrate_wallet_type,
+                            scan_blockchain,
+                        )
                         .await
                 })
             })
diff --git a/wallet/wallet-rpc-lib/src/rpc/server_impl.rs b/wallet/wallet-rpc-lib/src/rpc/server_impl.rs
index 93370d2e4..3008e606b 100644
--- a/wallet/wallet-rpc-lib/src/rpc/server_impl.rs
+++ b/wallet/wallet-rpc-lib/src/rpc/server_impl.rs
@@ -101,7 +101,7 @@ impl<N: NodeInterface + Clone + Send + Sync + Debug + 'static> ColdWalletRpcServ
                 whether_to_store_seed_phrase,
                 mnemonic,
                 passphrase,
-                ScanBlockchain::ScanAndWait,
+                ScanBlockchain::ScanNoWait,
             )
             .await
             .map(Into::<CreatedWallet>::into),
@@ -119,6 +119,7 @@ impl<N: NodeInterface + Clone + Send + Sync + Debug + 'static> ColdWalletRpcServ
                 path.into(),
                 password,
                 force_migrate_wallet_type.unwrap_or(false),
+                ScanBlockchain::ScanNoWait,
             )
             .await,
         )
diff --git a/wallet/wallet-rpc-lib/src/service/worker.rs b/wallet/wallet-rpc-lib/src/service/worker.rs
index 9d976d749..7e38098e3 100644
--- a/wallet/wallet-rpc-lib/src/service/worker.rs
+++ b/wallet/wallet-rpc-lib/src/service/worker.rs
@@ -174,6 +174,7 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static> WalletWorker<N> {
         wallet_path: PathBuf,
         password: Option<String>,
         force_migrate_wallet_type: bool,
+        scan_blockchain: ScanBlockchain,
     ) -> Result<(), ControllerError<N>> {
         utils::ensure!(
             self.controller.is_none(),
@@ -188,13 +189,22 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static> WalletWorker<N> {
             force_migrate_wallet_type,
         )?;
 
-        let controller = WalletController::new(
-            self.chain_config.clone(),
-            self.node_rpc.clone(),
-            wallet,
-            self.wallet_events.clone(),
-        )
-        .await?;
+        let controller = if scan_blockchain.should_wait_for_blockchain_scanning() {
+            WalletController::new(
+                self.chain_config.clone(),
+                self.node_rpc.clone(),
+                wallet,
+                self.wallet_events.clone(),
+            )
+            .await?
+        } else {
+            WalletController::new_unsynced(
+                self.chain_config.clone(),
+                self.node_rpc.clone(),
+                wallet,
+                self.wallet_events.clone(),
+            )
+        };
         self.controller.replace(controller);
 
         Ok(())


Test patch:
diff --git a/test/functional/wallet_orders.py b/test/functional/wallet_orders.py
index 6b7304e1e..e6676a86f 100644
--- a/test/functional/wallet_orders.py
+++ b/test/functional/wallet_orders.py
@@ -70,6 +70,7 @@ class WalletOrders(BitcoinTestFramework):
     async def switch_to_wallet(self, wallet, wallet_name):
         await wallet.close_wallet()
         await wallet.open_wallet(wallet_name)
+        await wallet.sync()
 
     def run_test(self):
         if 'win32' in sys.platform: