Skip to content

chore!: upgrade to minotari 5.0.0 - #1560

Merged
sdbondi merged 4 commits into
tari-project:developmentfrom
sdbondi:upgrade-tari-5.0.0
Sep 1, 2025
Merged

chore!: upgrade to minotari 5.0.0#1560
sdbondi merged 4 commits into
tari-project:developmentfrom
sdbondi:upgrade-tari-5.0.0

Conversation

@sdbondi

@sdbondi sdbondi commented Aug 29, 2025

Copy link
Copy Markdown
Member

Description

chore!: upgrade to minotari 5.0.0
test: fix some cucumbers

Summary by CodeRabbit

  • New Features

    • Wallet daemon: CreateAccount replaces CreateKey, outputs address/public_key, can set active and save to file.
    • Wallet SDK: derive account address from public key.
    • Indexer client: add peers over jRPC.
  • Changes

    • CLI: http_server_url replaces http_client_url; removed --enable-grpc and custom base-node flag.
    • Wallet daemon supports override keyring password via config.
    • Improved startup responsiveness and logging (including cucumber logs).
  • Documentation

    • README updated to use development branch flow and swarm init/start commands.
  • Chores

    • Dependency manifest realigned to new components/branches; libsqlite3-sys bumped; added ignore rule.

@coderabbitai

coderabbitai Bot commented Aug 29, 2025

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

Walkthrough

Repository-wide migration from tari_core/tari_key_manager to new component crates (tari_transaction_components, tari_node_components, tari_transaction_key_manager), switch from PaymentId to MemoField (bytes) for memo/payment_id fields, manifest/workspace updates to development branches, wallet-daemon API/config refactors, indexer/VN logging and epoch handling tweaks, and extensive integration-test rewrites to network-centric flows with relaxed height checks and cucumber logging.

Changes

Cohort / File(s) Summary
Repo housekeeping
/.gitignore, README.md, integration_tests/tests/log4rs/cucumber.yml
Add root ignore for cucumber-output-junit.xml; update README to use development branch and add swarm init/start steps; add a cucumber rolling log appender and attach it to the cucumber logger.
Workspace/patch/deps overhaul
/Cargo.toml
Replace many pinned git tags with branch = "development" for Tari deps; add tari_transaction_components, tari_node_components, tari_transaction_key_manager; bump libsqlite3-sys to 0.30.1; update [patch] blocks and local patch overrides to new component names.
Per-crate manifest updates
applications/*/Cargo.toml, clients/*/Cargo.toml, crates/*/Cargo.toml, integration_tests/Cargo.toml
Replace tari_core/tari_key_manager workspace deps with new component crates across multiple crates; add optional minotari_app_grpc; adjust tokio/dev features and add multiaddr to integration tests.
MemoField replaces PaymentId (core flows)
applications/tari_swarm_daemon/src/layer_one_transactions/submitter.rs, applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs, applications/tari_watcher/src/minotari.rs, integration_tests/*/steps/*
Replace PaymentId::Open usage with MemoField::new_open(...).to_bytes(); propagate creation errors; pass memo bytes in gRPC requests and test payloads.
Wallet daemon API / config / CLI refactor
applications/tari_walletd/src/cli.rs, .../config.rs, .../lib.rs, .../main.rs, integration_tests/src/wallet_daemon.rs, applications/tari_swarm_daemon/src/process_definitions/wallet_daemon_create_key.rs
Move SeedWords types to tari_common_types; rename CreateKey→CreateAccount (new CLI flags); add override_keyring_password config field; change walletd startup signatures to accept config + optional seed_words (drop global Cli); adjust spawn/create-account command and tests to new runner signature.
Validator / VN / crypto init changes
applications/tari_validator_node/src/lib.rs, applications/tari_validator_node/src/json_rpc/handlers.rs
Run preload_crypto_services() in spawn_blocking(...).await?; rebind ValidatorNodeSignature import to tari_transaction_components.
Swarm daemon process args & URLs
applications/tari_swarm_daemon/src/process_definitions/minotari_node.rs, .../minotari_wallet.rs
Remove --enable-grpc from Minotari node args; change console wallet flag from http_client_url to http_server_url; stop passing custom_base_node flag.
Manager / consensus import updates
applications/tari_swarm_daemon/src/process_manager/manager.rs
Repoint NetworkConsensus import from tari_core::consensustari_transaction_components::consensus.
Base node client and trait/type rebindings
clients/base_node_client/src/grpc.rs, .../traits.rs, .../types.rs
Use gRPC ValidatorNodeChange return type; remove local conversions; rebind BlockHeader, CodeTemplateRegistration, MicroMinotari, TransactionOutput imports to new component crates.
Epoch manager / oracle conversions & errors
crates/epoch_manager/src/epoch_event_oracle/event.rs, crates/epoch_oracles/src/base_layer/mod.rs
Add feature-gated TryFrom conversion from gRPC ValidatorNodeChange; rename error variant InvalidSideChainUtxoResponseInvalidBaseNodeResponse; switch to fallible conversion collection and update related imports/types.
Wallet SDK key manager migration
crates/wallet/sdk/src/apis/key_manager.rs, .../confidential_outputs.rs, .../accounts.rs, .../sdk.rs, .../lib.rs, .../models/key.rs
Migrate to TariKeyManager and untyped DerivedKey; remove RistrettoPublicKey generic from DerivedKey in public APIs; update error types to KeyManagerApiError and add CipherError; add AccountsApi::derive_account_address_from_public_key; move cipher/seed types to tari_common_types.
Indexer & network client tweaks
applications/tari_indexer/src/network_client.rs, integration_tests/src/indexer.rs
Move epoch-wait earlier in submit flow; adjust log messages; log committee fetching; add IndexerProcess.add_peer and use multiaddr for peers; use validator p2p ports for seeds.
Integration test infra & world model
integration_tests/src/lib.rs, .../util.rs, .../base_node.rs, .../validator_node.rs, .../wallet.rs, .../wallet_daemon.rs, .../wallet_daemon_cli.rs, .../network.rs, .../miner.rs, .../steps/*
Add cucumber_log helper and cucumber logger usage; refactor TariWorld (claim_proofs, substate_ids, default_payment_address, world init hook); rename portp2p_port; add VN consensus wait helper; move many test flows to wallet-daemon-driven burn/claim using ExtClaimBurnProof and MemoField bytes; relax many height checks from exact to "at least".
Feature files (Cucumber) updated
integration_tests/tests/features/*
Convert per-node setup to network-centric scenarios, replace commitment-based flows with BURN_PROOF-driven flows, and loosen scan-height assertions to lower-bound checks.
Small runtime/logging edits
integration_tests/src/miner.rs, integration_tests/src/base_node.rs, applications/tari_swarm_daemon/src/process_definitions/mod.rs
Increase poll interval in miner mines loop; add eprintln!/cucumber_log debug outputs; switch WalletDaemonCreateKey→WalletDaemonCreateAccount instantiation.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Tester
  participant World
  participant ConsoleWallet
  participant BaseNode
  participant Indexer
  participant WalletDaemon

  Tester->>World: boot network (base, console wallet, miner, indexer, walletd, VN)
  World->>BaseNode: mine initial blocks
  ConsoleWallet->>BaseNode: submit VN registration (payment_id = MemoField bytes)
  BaseNode-->>World: tx accepted / epoch updated
  Indexer->>World: scan to at least target height
  Tester->>WalletDaemon: authenticate (None) / override keyring password
  Note over WalletDaemon: walletd accessible at /json_rpc
Loading
sequenceDiagram
  autonumber
  actor Tester
  participant ConsoleWallet
  participant WalletDaemon
  participant BaseNode

  Tester->>ConsoleWallet: burn amount -> returns BURN_PROOF (ExtClaimBurnProof)
  Tester->>WalletDaemon: claim_burn(proof, account, max_fee)
  WalletDaemon->>BaseNode: submit claim tx (payment_id = MemoField::Burn bytes)
  BaseNode-->>WalletDaemon: tx_id
  Tester->>WalletDaemon: wait_transaction_result(tx_id, timeout)
  WalletDaemon-->>Tester: FinalizeResult (success/fail)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

Poem

A rabbit taps its tiny keys,
Swaps cores for components with a breeze.
Memos curl where payments used to be,
Wallets hum with seed and key.
Tests now hop to "at least" the height—
Cucumber logs glow through the night. 🐇🥕


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 716a3c3 and 3b06c81.

📒 Files selected for processing (9)
  • README.md (2 hunks)
  • applications/tari_swarm_daemon/src/process_definitions/mod.rs (1 hunks)
  • applications/tari_swarm_daemon/src/process_definitions/wallet_daemon_create_key.rs (2 hunks)
  • applications/tari_walletd/src/cli.rs (3 hunks)
  • applications/tari_walletd/src/main.rs (5 hunks)
  • crates/epoch_manager/src/epoch_event_oracle/event.rs (1 hunks)
  • integration_tests/tests/features/transfer.feature (5 hunks)
  • integration_tests/tests/log4rs/cucumber.yml (2 hunks)
  • integration_tests/tests/steps/network.rs (2 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions

Copy link
Copy Markdown

Test Results (CI)

395 tests   - 24   395 ✅ ± 0   44m 18s ⏱️ - 9m 25s
 56 suites  - 13     0 💤 ± 0 
  1 files    -  1     0 ❌  - 24 

Results for commit 1fefdf7. ± Comparison against base commit e0b97c2.

This pull request removes 24 tests.
Scenario: Claim and transfer confidential assets via wallet daemon: tests/features/wallet_daemon.feature:83:3
Scenario: Claim base layer burn funds with wallet daemon: tests/features/claim_burn.feature:9:3
Scenario: Claim validator fees: tests/features/claim_fees.feature:8:3
Scenario: Concurrent calls to the Counter template: tests/features/concurrency.feature:7:3
Scenario: Confidential transfer to account that does not previously exist: tests/features/transfer.feature:151:3
Scenario: Counter template registration and invocation multiple times: tests/features/counter.feature:46:3
Scenario: Counter template registration and invocation once: tests/features/counter.feature:8:3
Scenario: Create account and transfer faucets via wallet daemon: tests/features/wallet_daemon.feature:8:3
Scenario: Create and mint account NFT: tests/features/wallet_daemon.feature:125:3
Scenario: Create resource and mint in one transaction: tests/features/nft.feature:80:3
…

SWvheerden pushed a commit to tari-project/tari that referenced this pull request Sep 1, 2025
Description
---
fix: set validator registration value to 1000uT for localnet and igor

Motivation and Context
---
The transaction builder checks that you aren't sending less funds than
the fee cost. This causes a
registration sending 0 to fail. Send 1000 to cover for this.

How Has This Been Tested?
---
Tested registration in tari-ootle PR
(tari-project/tari-ootle#1560)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Raised the minimum validator node registration deposit to 1000
MicroMinotari on localnet and Igor.
* Users registering validator nodes on these networks must now provide
at least 1000 MicroMinotari as a deposit.
* No changes to public APIs or user interfaces; impact is limited to
validator registration requirements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
SWvheerden pushed a commit to SWvheerden/tari that referenced this pull request Sep 1, 2025
Description
---
fix: set validator registration value to 1000uT for localnet and igor

Motivation and Context
---
The transaction builder checks that you aren't sending less funds than
the fee cost. This causes a
registration sending 0 to fail. Send 1000 to cover for this.

How Has This Been Tested?
---
Tested registration in tari-ootle PR
(tari-project/tari-ootle#1560)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Raised the minimum validator node registration deposit to 1000
MicroMinotari on localnet and Igor.
* Users registering validator nodes on these networks must now provide
at least 1000 MicroMinotari as a deposit.
* No changes to public APIs or user interfaces; impact is limited to
validator registration requirements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
SWvheerden pushed a commit to tari-project/tari that referenced this pull request Sep 1, 2025
Description
---
fix: set validator registration value to 1000uT for localnet and igor

Motivation and Context
---
The transaction builder checks that you aren't sending less funds than
the fee cost. This causes a
registration sending 0 to fail. Send 1000 to cover for this.

How Has This Been Tested?
---
Tested registration in tari-ootle PR
(tari-project/tari-ootle#1560)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Raised the minimum validator node registration deposit to 1000
MicroMinotari on localnet and Igor.
* Users registering validator nodes on these networks must now provide
at least 1000 MicroMinotari as a deposit.
* No changes to public APIs or user interfaces; impact is limited to
validator registration requirements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
SWvheerden pushed a commit to tari-project/tari that referenced this pull request Sep 1, 2025
Description
---
fix(wallet): use minimum value promise in VN reg output

Motivation and Context
---
Base node validation for VN reg requires the minimum value promise to be
>= deposit amount

Ref tari-project/tari-ootle#1560

How Has This Been Tested?
---
In PR tari-project/tari-ootle#1560


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added an optional "minimum value promise" for pay-to-self transactions
and UTXO aggregation.
* Propagated across wallet transaction flows and advanced transaction
options so it's available where outputs are constructed.
* Defaults to zero when not specified, preserving existing behavior and
workflows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@sdbondi
sdbondi marked this pull request as ready for review September 1, 2025 13:18
@sdbondi
sdbondi force-pushed the upgrade-tari-5.0.0 branch 2 times, most recently from 2e05e6c to 7a63f69 Compare September 1, 2025 13:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (9)
applications/tari_swarm_daemon/src/process_manager/manager.rs (2)

451-484: Bug: inverted existence check and misuse of envs when creating instances

Logic is flipped: you error when the instance does not exist, and you try to read envs() from a would-be duplicate. This prevents creation and can panic later.

-                let Some(instance) = self.instance_manager.instances().find(|i| i.name() == name) else {
-                    if reply
-                        .send(Err(anyhow!(
-                            "Instance with name '{name}' already exists. Please choose a different name",
-                        )))
-                        .is_err()
-                    {
-                        log::warn!("Request cancelled before response could be sent")
-                    }
-                    return Ok(());
-                };
-
-                let envs = instance.envs().to_vec();
+                if self
+                    .instance_manager
+                    .instances()
+                    .any(|i| i.name() == name)
+                {
+                    let _ = reply.send(Err(anyhow!(
+                        "Instance with name '{name}' already exists. Please choose a different name",
+                    )));
+                    return Ok(());
+                }
+
+                // No prior instance with this name; start with no additional env vars
+                let envs = vec![];

821-824: Compile-time type error in log expression

min_expected_blocks * initial_emission_amount mixes u64 with a non-primitive amount type. Use .as_u64() as you did in the comparison above.

-                min_expected_blocks * initial_emission_amount
+                min_expected_blocks * initial_emission_amount.as_u64()
clients/base_node_client/src/grpc.rs (2)

72-79: Avoid unwrap(); propagate connection errors.

This can panic under transient network issues. Use ? to bubble up BaseNodeClientError instead.

-        let inner = self.connection().await.unwrap();
+        let inner = self.connection().await?;

25-46: Update downstream ValidatorNodeChange usages and conversions
Multiple consumers still assume the old local type/signature—these must be updated to use the gRPC message or the TryFrom impl:

  • crates/epoch_oracles/src/base_layer/mod.rs (L463–L467): get_validator_node_changes now returns Vec<grpc::ValidatorNodeChange>; adjust the call site to import the gRPC type and convert each element to your local enum.
  • crates/epoch_oracles/src/configured/oracle.rs (L134–L136): mapping via vn.claim_key/vn.public_key is invalid for the gRPC message; replace with ValidatorNodeChange::try_from(vn)? or explicitly match on vn.change.
crates/wallet/sdk/src/sdk.rs (2)

93-121: Avoid bricking existing wallets when RecoveryNeeded is missing.
Older stores may not have ConfigKey::RecoveryNeeded set. Default and persist false instead of erroring.

-                let requires_recovery = self.config_api().get(ConfigKey::RecoveryNeeded).optional()?;
-                // This should have been set - it is an error if it is not
-                requires_recovery.ok_or_else(|| WalletSdkError::InvariantError {
-                    details: "Cipher seed already initialized but recovery_needed not set.".to_string(),
-                })
+                let requires_recovery = self.config_api().get(ConfigKey::RecoveryNeeded).optional()?;
+                let requires_recovery = match requires_recovery {
+                    Some(v) => v,
+                    None => {
+                        warn!(target: LOG_TARGET, "RecoveryNeeded flag missing; defaulting to false for backward compatibility.");
+                        self.config_api().set(ConfigKey::RecoveryNeeded, &false, false)?;
+                        false
+                    },
+                };
+                Ok(requires_recovery)

373-386: Remove stale KeyManagerError variants in APIs The errors KeyManagerError in crates/wallet/sdk/src/apis/key_manager.rs:261 and crates/wallet/sdk/src/apis/stealth_scanner.rs:247 must be replaced with the updated error types or removed.

crates/epoch_oracles/src/base_layer/mod.rs (1)

119-121: Critical: last_epoch_hash loaded from the wrong store key.
load_initial_state reads BaseLayerLastScannedBlockHash instead of BaseLayerLastEpochHash; set_last_epoch_block writes BaseLayerLastEpochHash. This breaks epoch hash recovery after restarts.

Apply:

-        self.last_epoch_hash = self
-            .store
-            .get(StoreKey::BaseLayerLastScannedBlockHash.as_key_bytes())
+        self.last_epoch_hash = self
+            .store
+            .get(StoreKey::BaseLayerLastEpochHash.as_key_bytes())
             .map_err(BaseLayerOracleError::StoreError)?;

Also applies to: 573-579

integration_tests/tests/steps/wallet.rs (1)

79-110: Fix type mismatch and brittle timeout check in balance wait loop.

iterations defaults to i32 and is compared to a u64. Also use >= to avoid off-by-one surprises.

Apply this diff:

-    let mut iterations = 0;
+    let mut iterations: u64 = 0;
@@
-        if iterations == MAX_WAIT_TIME_SECS.div_ceil(2) {
+        if iterations >= MAX_WAIT_TIME_SECS.div_ceil(2) {
crates/wallet/sdk/src/apis/key_manager.rs (1)

149-160: Bug: inconsistent branch identifier used for persistence can desync indices.

Everywhere else you use branch.as_ref() as the store key, but here you insert using key_manager.branch_seed. If these ever differ, last_index()/set_active will read/update a different row, causing repeated index resets or duplicate rows. Use the same identifier for all store ops.

Apply:

-        tx.key_manager_insert(&key_manager.branch_seed, key_manager.key_index())?;
+        tx.key_manager_insert(branch.as_ref(), key_manager.key_index())?;

Optional safety net: Add a uniqueness constraint on the key-manager table for (branch) to fail fast on mismatches.

🧹 Nitpick comments (68)
integration_tests/src/templates/faucet/src/lib.rs (1)

46-48: Prefer explicit conversion for clarity and trait stability

1000.into() relies on From<u64> for Amount. If that impl ever changes, this could break inference. Consider being explicit.

-            self.take_amount_of_free_coins(1000.into())
+            self.take_amount_of_free_coins(Amount::from(1000))
applications/tari_indexer/src/network_client.rs (2)

52-54: Good guard; add timing/observability (and optional timeout) to avoid blind waits

Keeping this wait is sensible. Add a quick timing log so we can see if/when this is a bottleneck. Optional: wrap with a configurable timeout if hangs are a concern.

Apply:

-        // Ensure initial scanning has completed to ensure an accurate epoch
-        self.epoch_manager.wait_for_initial_scanning_to_complete().await?;
+        // Ensure initial scanning has completed to ensure an accurate epoch
+        let t0 = std::time::Instant::now();
+        self.epoch_manager.wait_for_initial_scanning_to_complete().await?;
+        log::debug!(target: LOG_TARGET, "Initial scanning completed in {:?}", t0.elapsed());

(Optional timeout sketch outside this hunk)

// use tokio::time::{timeout, Duration};
// timeout(Duration::from_secs(config.initial_scan_timeout_secs),
//     self.epoch_manager.wait_for_initial_scanning_to_complete()
//).await.map_err(|_| NetworkClientError::EpochManagerError(EpochManagerError::Other("initial scan timeout".into())))??;

151-157: Helpful context log; consider debug level and add shard-group count

The new log is useful. In high-QPS paths, consider debug! to reduce noise, and after building all_members add the unique shard-group count for correlation.

Add after committee_size is computed (outside this hunk):

-        let committee_size = all_members.len();
+        let committee_size = all_members.len();
+        log::debug!(target: LOG_TARGET, "Resolved committees for {} unique shard groups at epoch {}", committee_size, epoch);

Nit: committee_size actually represents the number of shard groups here, not the number of validators. Consider renaming and adjusting the error message for clarity:

-        let committee_size = all_members.len();
+        let num_shard_groups = all_members.len();
-            return Err(NetworkClientError::AllValidatorsFailed {
-                committee_size,
+            return Err(NetworkClientError::AllValidatorsFailed {
+                committee_size: num_shard_groups,
                 last_error,
             });

And in the error display (outside this hunk):

-    #[error("Rpc call failed for all ({committee_size}) validators: {}", .last_error.as_deref().unwrap_or("unknown"))]
+    #[error("RPC calls failed for all ({committee_size}) shard groups: {}", .last_error.as_deref().unwrap_or("unknown"))]
applications/tari_swarm_daemon/src/process_manager/manager.rs (2)

807-812: Avoid potential panic: handle empty consensus constants gracefully

pop().unwrap() will panic if the list is empty. Return a proper error instead.

-        let constants = NetworkConsensus::from(convert_network_to_l1_network(&self.network))
-            .create_consensus_constants()
-            .pop()
-            .unwrap();
+        let constants = NetworkConsensus::from(convert_network_to_l1_network(&self.network))
+            .create_consensus_constants()
+            .pop()
+            .ok_or_else(|| anyhow!("No consensus constants available for selected network"))?;

616-626: Return full path, not just the filename

You create the file at out_path.join(file_name) but return only file_name. Callers likely expect the full path to the created file.

-        Ok(file_name)
+        Ok(path)

Would you like me to scan callers to confirm expectations?

README.md (1)

91-97: Wording nit: it’s a tag, not a branch

The commands fetch/checkout a tag. Adjust the wording for accuracy.

-`cd` into `tari` and change the branch `v5.0.0-pre.8`:
+`cd` into `tari` and checkout the tag `v5.0.0-pre.8`:
applications/tari_swarm_daemon/src/process_definitions/minotari_wallet.rs (1)

67-68: Verify http_server_url semantics and avoid port clash with base node.

You’re setting wallet http_server_url to the base node HTTP port. If this flag is for the wallet’s own server, it will collide; if it configures a client endpoint, the name is misleading.

Option A (wallet hosts its own HTTP server):

-            .arg(format!(
-                "-pwallet.http_server_url=http://{listen_ip}:{base_node_api_port}"
-            ))
+        let wallet_http_port = context.get_free_port("wallet_http").await?;
+            .arg(format!(
+                "-pwallet.http_server_url=http://{listen_ip}:{wallet_http_port}"
+            ))

Option B (wallet needs BN HTTP client URL): keep using the client flag:

- "-pwallet.http_server_url=http://{listen_ip}:{base_node_api_port}"
+ "-pwallet.http_client_url=http://{listen_ip}:{base_node_api_port}"

Please confirm the intended flag in minotari 5.0.0 CLI.

integration_tests/src/templates/basic_nft/src/lib.rs (2)

51-53: Access rules set to allow_all for tests (LGTM).

Appropriate for test templates; ensure no prod templates rely on this.

Consider a comment like “test-only: allow_all” to prevent copy/paste into prod code.

Also applies to: 68-70


72-74: Be explicit about quantity type to aid readability.

withdraw(1) is fine if Into is implemented; using Amount::one() (or an explicit Amount) can reduce ambiguity.

-            self.vault.withdraw(1)
+            self.vault.withdraw(Amount::one())
integration_tests/tests/steps/miner.rs (2)

33-33: Consider timeout over loop counter.

A bounded timeout is clearer than iter_count with fixed sleep; also mitigates flakiness if sleep changes.

-            tokio::time::sleep(std::time::Duration::from_millis(500)).await;
-            if iter_count > 100 {
+            tokio::time::sleep(std::time::Duration::from_millis(500)).await;
+            if iter_count >= 100 {
                 panic!("Timed out waiting for tip height to reach {}", start_tip + num_blocks);
             }

Or:

tokio::time::timeout(std::time::Duration::from_secs(50), async {
    while tip.height_of_longest_chain < start_tip + num_blocks {
        tip = client.get_tip_info().await.unwrap();
        tokio::time::sleep(std::time::Duration::from_millis(500)).await;
    }
}).await.expect("Timed out waiting for tip height");

39-42: Prefer structured logging over eprintln!.

Use the repo’s logging (log/tracing) so messages appear in CI logs consistently.

-        eprintln!(
-            "Base node {} reached tip height {}",
-            bn.name, tip.height_of_longest_chain
-        );
+        log::info!("Base node {} reached tip height {}", bn.name, tip.height_of_longest_chain);
applications/tari_watcher/Cargo.toml (1)

15-15: Consider disabling default features for parity.

Several crates set default-features = false for tari_transaction_components; align here unless defaults are required.

Apply:

-tari_transaction_components = { workspace = true } # Used for VN registration signature
+tari_transaction_components = { workspace = true, default-features = false } # Used for VN registration signature
crates/epoch_manager/Cargo.toml (1)

13-13: Disable default features on minotari_app_grpc to avoid unintended pulls.

Unless you rely on its defaults, keep it lean.

-minotari_app_grpc = { workspace = true, optional = true }
+minotari_app_grpc = { workspace = true, optional = true, default-features = false }
applications/tari_validator_node/src/lib.rs (1)

115-115: Add context to JoinError from spawn_blocking.

Propagate a clearer error if the blocking task panics or the runtime is shutting down.

Apply:

-    task::spawn_blocking(preload_crypto_services).await?;
+    use anyhow::Context;
+    task::spawn_blocking(preload_crypto_services)
+        .await
+        .context("preloading crypto services (spawn_blocking)")?;
applications/tari_swarm_daemon/Cargo.toml (1)

12-12: Align default‐features usage here with clients/base_node_client (optional).
Only clients/base_node_client/Cargo.toml currently sets default-features = false for tari_transaction_components. If this daemon doesn’t rely on any of the crate’s default features, consider adding default-features = false to shrink the dependency graph:

-tari_transaction_components = { workspace = true } # Used for VN registration signature
+tari_transaction_components = { workspace = true, default-features = false } # Used for VN registration signature
applications/tari_walletd/src/config.rs (1)

90-110: Gate the password override for non-production builds

Reduce risk surface by feature-gating or env-guarding this field so it’s unusable in prod configs.

Example approach (outline):

  • Add a cargo feature e.g. dangerous_password_override.
  • Under that feature, include the field; otherwise, reject/ignore it on load.
applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs (1)

57-59: Use anyhow::Context and avoid extra allocation for the memo

Slightly cleaner error propagation and fewer conversions.

-            payment_id: MemoField::new_open("Burn funds in swarm".as_bytes().to_vec(), TxType::Burn)
-                .map_err(|e| anyhow!("Failed to create MemoField: {e}"))?
-                .to_bytes(),
+            payment_id: {
+                let bytes = MemoField::new_open(b"Burn funds in swarm".to_vec(), TxType::Burn)
+                    .context("Failed to create MemoField")?
+                    .to_bytes();
+                bytes
+            },

Add the import:

use anyhow::Context;
integration_tests/src/wallet_daemon_cli.rs (1)

904-906: Helper now always returns an authed client — consider a fallible variant.

Add a try_get_auth_wallet_daemon_client returning Result to avoid panics when the name is wrong, while keeping this infallible helper for tests.

Example addition (outside this hunk):

pub async fn try_get_auth_wallet_daemon_client(
    world: &TariWorld,
    name: &str,
) -> anyhow::Result<WalletDaemonClient> {
    let wd = world
        .wallet_daemons
        .get(name)
        .ok_or_else(|| anyhow::anyhow!("No wallet daemon named {}", name))?;
    Ok(wd.get_authed_client().await)
}
integration_tests/src/validator_node.rs (1)

98-115: Resilient RPC errors in wait_for_consensus_to_start
Replace unwrap() with a match to log transient RPC errors and continue polling under the same 60 s timeout.

-        loop {
-            let resp = client.get_consensus_status().await.unwrap();
-            if resp.state == "Running" {
-                return;
-            }
+        loop {
+            match client.get_consensus_status().await {
+                Ok(resp) if resp.state == "Running" => return,
+                Ok(_) => {},
+                Err(e) => log::warn!("get_consensus_status failed: {e}"),
+            }
             attempts -= 1;
             if attempts == 0 {
                 panic!(
                     "Validator node did not start consensus in time: status: {}, epoch: {}",
-                    resp.state, resp.epoch
+                    client.get_consensus_status().await.map(|r| r.state).unwrap_or_else(|_| "<err>".into()),
+                    client.get_consensus_status().await.map(|r| r.epoch).unwrap_or_default()
                 );
             }
             tokio::time::sleep(std::time::Duration::from_secs(1)).await;
         }
integration_tests/src/wallet.rs (4)

119-126: Remove stale, commented base-node key/port code.
Dead code adds noise and confuses future readers. Safe to delete.

Apply:

-    // let base_node_public_key = world
-    //     .base_nodes
-    //     .get(&base_node_name)
-    //     .unwrap()
-    //     .identity
-    //     .public_key()
-    //     .clone();
-    // let base_node_port = world.base_nodes.get(&base_node_name).unwrap().port;

179-183: Delete commented base_node_service_peers block.
If custom base node is deprecated in 5.0.0, keep history in git, not comments.

-            // wallet_config.wallet.base_node_service_peers = Some(format!(
-            //     "{}::/ip4/127.0.0.1/tcp/{}",
-            //     base_node_public_key, base_node_port
-            // ));

220-233: Dropped connectivity wait can cause flakiness; add a lightweight readiness check or remove block.
Consider polling identify() + one base-node HTTP call, or delete this block entirely.

-    // let mut status = wallet_client.get_network_status(Empty {}).await.unwrap().into_inner();
-    // let mut counter = 0;
-    // while status.status != ConnectivityStatus::Online as i32 {
-    //     eprintln!(
-    //         "Waiting for wallet to connect to base node {} on port {} (status: {:?})",
-    //         base_node_name, base_node_port, status
-    //     );
-    //     tokio::time::sleep(Duration::from_secs(1)).await;
-    //     counter += 1;
-    //     if counter > 20 {
-    //         panic!("Wallet failed to connect to base node");
-    //     }
-    //     status = wallet_client.get_network_status(Empty {}).await.unwrap().into_inner();
-    // }

Optional readiness (outside this block):

// After identify():
// tokio::time::timeout(Duration::from_secs(20), async {
//     // ping base node HTTP or check tip height > 0 via wallet RPC if available
// }).await.expect("wallet/base-node not ready in time");

71-97: Retry loop off-by-one and no connect timeout.
Currently allows 12 tries and unbounded connect(). Add connect_timeout and fix counter.

-        let endpoint = Endpoint::from_str(&wallet_addr).unwrap();
-        let mut attempts = 0;
+        let endpoint = Endpoint::from_str(&wallet_addr)
+            .expect("Invalid wallet GRPC address")
+            .connect_timeout(Duration::from_secs(5));
+        let mut attempts = 0usize;
         let channel = loop {
             if self.handle.is_finished() {
                 panic!("Wallet thread has ended");
             }
-            match endpoint.connect().await {
+            attempts += 1;
+            match endpoint.connect().await {
                 Ok(channel) => break channel,
                 Err(e) => {
                     eprintln!(
                         "Attempt: {}/10 Could not connect to wallet GRPC address {}: {}",
-                        attempts, wallet_addr, e
+                        attempts, wallet_addr, e
                     );
-                    if attempts > 10 {
+                    if attempts >= 10 {
                         panic!("Failed to connect to wallet GRPC address {}", wallet_addr);
                     }
                     tokio::time::sleep(Duration::from_secs(1)).await;
-                    attempts += 1;
                 },
             }
         };
applications/tari_swarm_daemon/src/layer_one_transactions/submitter.rs (2)

62-68: Use as_bytes() before to_vec() for signatures to avoid trait ambiguity.
Keeps consistency with exit path below and avoids relying on impls that may change.

-                        validator_node_signature: Some(grpc::Signature {
-                            public_nonce: registration.signature.public_nonce().to_vec(),
-                            signature: registration.signature.signature().to_vec(),
-                        }),
+                        validator_node_signature: Some(grpc::Signature {
+                            public_nonce: registration.signature.public_nonce().as_bytes().to_vec(),
+                            signature: registration.signature.signature().as_bytes().to_vec(),
+                        }),

75-79: Also convert optional sidechain key via as_bytes().
Prevents relying on Into<Vec> impls.

-                        sidechain_deployment_key: registration
-                            .sidechain_public_key
-                            .map(|key| key.to_vec())
-                            .unwrap_or_default(),
+                        sidechain_deployment_key: registration
+                            .sidechain_public_key
+                            .map(|key| key.as_bytes().to_vec())
+                            .unwrap_or_default(),
applications/tari_watcher/src/minotari.rs (2)

134-141: Prefer as_bytes() for keys/signatures to ensure explicit conversion.
Matches other call sites and avoids implicit Vec conversions.

-                validator_node_public_key: info.public_key.to_vec(),
+                validator_node_public_key: info.public_key.as_bytes().to_vec(),
                 validator_node_signature: Some(grpc::Signature {
-                    public_nonce: info.signature.public_nonce().to_vec(),
-                    signature: info.signature.signature().to_vec(),
+                    public_nonce: info.signature.public_nonce().as_bytes().to_vec(),
+                    signature: info.signature.signature().as_bytes().to_vec(),
                 }),
-                validator_node_claim_public_key: info.claim_fees_public_key.to_vec(),
+                validator_node_claim_public_key: info.claim_fees_public_key.as_bytes().to_vec(),

194-201: Make signature bytes extraction explicit.
Consistency with exit path and other modules.

                         validator_node_signature: Some(grpc::Signature {
-                            public_nonce: registration.signature.public_nonce().to_vec(),
-                            signature: registration.signature.signature().to_vec(),
+                            public_nonce: registration.signature.public_nonce().as_bytes().to_vec(),
+                            signature: registration.signature.signature().as_bytes().to_vec(),
                         }),
Cargo.toml (2)

140-147: Consider disabling default features on new component crates at the workspace level.

To prevent accidental feature creep and keep crates in control of features, set default-features = false for these workspace-scoped deps (if supported by the crates).

-tari_transaction_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
-tari_node_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
-tari_transaction_key_manager = { git = "https://github.com/tari-project/tari.git", branch = "development" }
+tari_transaction_components = { git = "https://github.com/tari-project/tari.git", branch = "development", default-features = false }
+tari_node_components = { git = "https://github.com/tari-project/tari.git", branch = "development", default-features = false }
+tari_transaction_key_manager = { git = "https://github.com/tari-project/tari.git", branch = "development", default-features = false }

205-205: libsqlite3-sys 0.30.1: consider bundled to avoid system-SQLite mismatches in CI.

This crate often fails on CI/macOS without a consistent SQLite. Enabling bundled trades a small build-time cost for reliability.

-libsqlite3-sys = "0.30.1"
+libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }

If you prefer system SQLite, ensure runners have a compatible lib and headers; otherwise expect intermittent link errors.

integration_tests/tests/features/state_sync.feature (1)

47-48: Nit: prefer “And” after the first Then for consistency.

Pure style; earlier you used “Then … And …”. Consider aligning here.

-Then VN has scanned to at least height 50
-Then VN2 has scanned to at least height 50
+Then VN has scanned to at least height 50
+And VN2 has scanned to at least height 50
integration_tests/src/util.rs (1)

12-15: Centralize the log target and consider a macro for zero-cost formatting.

  • Define a shared constant for the target to avoid "cucumber" string duplication across files.
  • Optional: provide a cucumber! macro so call sites don’t need format! (avoids eager allocation).

Apply this minimal change for the target:

+pub const CUCUMBER_LOG_TARGET: &str = "cucumber";
+
 pub fn cucumber_log<T: AsRef<str>>(msg: T) {
   // eprintln!("CUCUMBER: {}", msg.as_ref());
-  info!(target: "cucumber", "{}", msg.as_ref());
+  info!(target: CUCUMBER_LOG_TARGET, "{}", msg.as_ref());
 }

Optional macro to add (usage: cucumber!("Base node identity: {}", id)):

#[macro_export]
macro_rules! cucumber {
    ($($arg:tt)*) => {
        ::log::info!(target: "cucumber", $($arg)*);
    };
}
integration_tests/tests/features/epoch_change.feature (1)

82-82: Commented expectation updated; consider pruning or tagging the scenario.

Either remove the commented block or guard it with a tag to avoid drift.

integration_tests/src/base_node.rs (1)

71-71: Route logs via cucumber_log — LGTM.

Consistent with the new test logging approach.

If you adopt the cucumber! macro suggested in util.rs, update these call sites to avoid format!:

- cucumber_log(format!("Base node identity: {}", base_node_identity));
+ cucumber!("Base node identity: {}", base_node_identity);

- cucumber_log(format!("Using base_node temp_dir: {}", temp_dir.display()));
+ cucumber!("Using base_node temp_dir: {}", temp_dir.display());

Also applies to: 97-97

integration_tests/tests/log4rs/cucumber.yml (1)

138-144: Confirm dual-target logging intent for cucumber.

Appending to both cucumber and ootle increases I/O and duplicates records; keep only cucumber if separation is desired.

   cucumber:
     level: debug
     appenders:
-      - cucumber
-      - ootle
+      - cucumber
     additive: false
crates/wallet/sdk/src/apis/accounts.rs (1)

57-59: Avoid duplicate logic—delegate to the free function.

-    pub fn derive_account_address_from_public_key(&self, public_key: &RistrettoPublicKeyBytes) -> ComponentAddress {
-        derive_component_address_from_public_key(&ACCOUNT_TEMPLATE_ADDRESS, public_key)
-    }
+    pub fn derive_account_address_from_public_key(&self, public_key: &RistrettoPublicKeyBytes) -> ComponentAddress {
+        super::accounts::derive_account_address_from_public_key(public_key)
+    }

Alternatively, deprecate the free function and keep only the method for a single API surface.

integration_tests/tests/features/wallet_daemon.feature (2)

107-107: Wording nit: “to proof” → “to produce proof” (if step regex allows)

If step definitions aren’t strict, consider:

-When I burn 1000T on wallet NETWORK_CONSOLE_WALLET to proof BURN_PROOF for wallet daemon WALLET_D
+When I burn 1000T on wallet NETWORK_CONSOLE_WALLET to produce proof BURN_PROOF for wallet daemon WALLET_D

If strict, ignore this to avoid breaking the matcher.


114-114: Minor wording: duplicate “address”

If the step matcher permits, simplify:

-When I convert commitment in proof BURN_PROOF into COMM_ADDRESS address
+When I convert commitment in proof BURN_PROOF into COMM_ADDRESS
crates/wallet/sdk/src/lib.rs (1)

15-15: Alias WalletSecretKey now points to DerivedKey — clarify semantics to avoid confusion.
If this is a key handle/derivation output (not a raw secret scalar), consider documenting to prevent misuse.

Apply doc comment for clarity:

- pub type WalletSecretKey = tari_transaction_components::key_manager::tari_key_manager::DerivedKey;
+ /// Alias to the wallet key manager's DerivedKey type used for derived wallet keys.
+ pub type WalletSecretKey = tari_transaction_components::key_manager::tari_key_manager::DerivedKey;
integration_tests/tests/steps/indexer.rs (1)

49-76: “At least height” check — good; tweak assertion text and consider a timeout helper.
Logic with >= removes flakiness. Update panic text to match the new condition.

-            panic!(
-                "Indexer {} did not scan to block height {}. Current height: {}",
-                name, block_height, stats.current_block_height
-            );
+            panic!(
+                "Indexer {} did not scan to at least block height {}. Current height: {}",
+                name, block_height, stats.current_block_height
+            );

Optional: extract the “poll with reset-on-progress and max wait” into a reusable helper or drive remaining from the configured scanning interval.

integration_tests/src/indexer.rs (2)

73-84: Avoid unwrap() in add_peer; return a Result to surface dial failures.
Panicking here makes test failures opaque. Propagate the client error.

-    pub async fn add_peer(&self, public_key: RistrettoPublicKeyBytes, port: u16) {
+    pub async fn add_peer(
+        &self,
+        public_key: RistrettoPublicKeyBytes,
+        port: u16,
+    ) -> Result<(), tari_indexer_client::IndexerClientError> {
         let mut jrpc_client = self.get_jrpc_indexer_client();
-        jrpc_client
+        jrpc_client
             .add_peer(AddPeerRequest {
                 public_key,
                 addresses: vec![multiaddr!(Ip4([127, 0, 0, 1]), Tcp(port))],
                 wait_for_dial: true,
             })
-            .await
-            .unwrap();
+            .await
+            .map(|_| ())
     }

Call sites can ? and add context.


151-159: Prefer 127.0.0.1 over localhost for client endpoints.
Minor portability tweak to avoid IPv6/hosts resolution surprises.

You can change both constructors to:

let endpoint: Url = Url::parse(&format!("http://127.0.0.1:{}", self.json_rpc_port)).unwrap();
// and similarly for GraphQL
applications/tari_walletd/src/cli.rs (1)

131-138: Update CreateAccount help text
Change the about to reflect account creation and options:

-    #[clap(about = "Generate a new key and output the public key")]
+    #[clap(about = "Create a new account; optionally set it active and/or write the public key to a file")]
     CreateAccount {
         #[clap(long, alias = "key")]
         key_index: Option<u64>,
         #[clap(long)]
         set_active: bool,
         #[clap(long, alias = "output", short = 'o')]
         output_path: Option<PathBuf>,
     },

Dispatch for Subcommand::CreateAccount is already wired in main.rs:68–71.

integration_tests/src/miner.rs (2)

84-90: Prefer &str over &String for miner_name.

Takes a borrowed String where a string slice suffices; avoids needless specificity.

-async fn create_base_node_client(world: &TariWorld, miner_name: &String) -> BaseNodeClient {
+async fn create_base_node_client(world: &TariWorld, miner_name: &str) -> BaseNodeClient {
     let miner = world.miners.get(miner_name).unwrap();

76-81: Replace fixed sleep with a wait-on-condition to reduce flakiness.

A hardcoded 100ms may be racy under load/CI. Poll the base node for template availability or mempool drain with a bounded timeout/retry.

integration_tests/tests/features/claim_burn.feature (4)

17-17: Mempool timing: 10s may be tight.

Consider a longer bounded wait or a polling step with backoff to reduce flakes on CI.

Also applies to: 38-38


18-19: Coupling “mine N blocks” with “scanned to ≥ height” can still race.

Prefer a single eventual condition like “wait for VN scanned to ≥ H” (optionally mining as needed) to avoid timing gaps between mining and scanning.

Also applies to: 39-40


14-14: Trim trailing whitespace.

Minor formatting nit in these steps.

-    When I burn 10T on wallet NETWORK_CONSOLE_WALLET to proof BURN_PROOF for wallet daemon WALLET_D 
+    When I burn 10T on wallet NETWORK_CONSOLE_WALLET to proof BURN_PROOF for wallet daemon WALLET_D

Also applies to: 35-35


45-47: Assert failure semantics for double-claim.

If available, assert a specific error code/message to make the negative case deterministic, not just “it fails”.

clients/base_node_client/src/grpc.rs (2)

126-131: Public API now exposes gRPC types — confirm callers and bindings.

Returning grpc::ValidatorNodeChange couples the client API to transport. If intentional, ensure all consumers (Rust and TS) are updated; otherwise consider an internal domain type with TryFrom.

Optional readability tweak:

-    ) -> Result<Vec<minotari_app_grpc::tari_rpc::ValidatorNodeChange>, BaseNodeClientError> {
+    ) -> Result<Vec<grpc::ValidatorNodeChange>, BaseNodeClientError> {

And keep:

-        let changes = result.changes;
-        Ok(changes)
+        Ok(result.changes)

Also applies to: 140-142


76-93: Error context for mempool stream.

Current Err maps to ConnectionError after warn!. Consider preserving the source error for callers.

-                Err(e) => {
-                    warn!(target: LOG_TARGET, "Error getting mempool transaction count: {}", e);
-                    return Err(BaseNodeClientError::ConnectionError);
-                },
+                Err(e) => {
+                    warn!(target: LOG_TARGET, "Error getting mempool transaction count: {}", e);
+                    return Err(e.into());
+                },
integration_tests/tests/steps/common.rs (1)

10-21: Improve log context and guard against silent overwrites.
Include the proof name in the log and assert if a duplicate key would overwrite an existing substate id.

-    cucumber_log(format!(
-        "Converted commitment {} into address: {}",
-        proof.claim_proof.commitment, address
-    ));
-    world.substate_ids.insert(new_name, address.into());
+    cucumber_log(format!(
+        "Converted commitment in proof {} (commitment: {}) into address {}",
+        proof_name, proof.claim_proof.commitment, address
+    ));
+    let prev = world.substate_ids.insert(new_name.clone(), address.into());
+    assert!(prev.is_none(), "Substate id '{}' already exists", new_name);
integration_tests/tests/steps/network.rs (1)

22-26: Define block-count constants to avoid mismatched logs.
Centralize “10” and “20” to prevent future drift.

-    const BASE_NODE_NAME: &str = "NETWORK_BASE_NODE";
-    const CONSOLE_WALLET_NAME: &str = "NETWORK_CONSOLE_WALLET";
+    const BASE_NODE_NAME: &str = "NETWORK_BASE_NODE";
+    const CONSOLE_WALLET_NAME: &str = "NETWORK_CONSOLE_WALLET";
     const MINER_NAME: &str = "NETWORK_MINER";
-    const INDEXER_NAME: &str = "NETWORK_INDEXER";
+    const INDEXER_NAME: &str = "NETWORK_INDEXER";
+    const BLOCKS_INITIAL: u64 = 10;
+    const BLOCKS_POST_REG: u64 = 20;

And use them below:

-    miner::miner_mines_new_blocks(world, MINER_NAME.to_string(), 10).await;
-    cucumber_log("Mined 10 blocks");
+    miner::miner_mines_new_blocks(world, MINER_NAME.to_string(), BLOCKS_INITIAL).await;
+    cucumber_log(&format!("Mined {} blocks", BLOCKS_INITIAL));

-    miner::miner_mines_new_blocks(world, MINER_NAME.to_string(), 20).await;
-    cucumber_log("Mined 26 blocks");
-    indexer::indexer_has_scanned_to_at_least_height(world, INDEXER_NAME.to_string(), 20).await;
-    cucumber_log("Indexer has scanned up to or past height 26");
+    miner::miner_mines_new_blocks(world, MINER_NAME.to_string(), BLOCKS_POST_REG).await;
+    cucumber_log(&format!("Mined {} blocks", BLOCKS_POST_REG));
+    indexer::indexer_has_scanned_to_at_least_height(world, INDEXER_NAME.to_string(), BLOCKS_POST_REG).await;
+    cucumber_log(&format!(
+        "Indexer has scanned up to or past height {}",
+        BLOCKS_POST_REG
+    ));
applications/tari_walletd/src/lib.rs (1)

65-69: Prefer owning SeedWords to enable secure zeroization.
Passing Option<&SeedWords> prevents wiping secrets. Take Option and pass .as_ref() to the SDK.

Apply:

-pub async fn run_tari_ootle_walletd(
-    config: ApplicationConfig,
-    seed_words: Option<&SeedWords>,
+pub async fn run_tari_ootle_walletd(
+    config: ApplicationConfig,
+    seed_words: Option<SeedWords>,
     shutdown_signal: ShutdownSignal,
 ) -> Result<(), anyhow::Error> {
@@
-    let needs_seed_recovery = wallet_sdk.initialize_cipher_seed(seed_words)?;
+    let needs_seed_recovery = wallet_sdk.initialize_cipher_seed(seed_words.as_ref())?;

Optionally drop the owned seed after use to limit lifetime.

Also applies to: 76-76

crates/epoch_oracles/src/base_layer/mod.rs (1)

469-477: Don’t fail the whole scan on a single malformed VN change.
Degrade gracefully: log and skip bad entries; emit changes for the valid ones.

Apply:

-                let node_changes = node_changes
-                    .into_iter()
-                    .map(TryInto::try_into)
-                    .collect::<Result<Vec<_>, _>>()
-                    .map_err(|e| {
-                        BaseLayerOracleError::InvalidBaseNodeResponse(format!(
-                            "Failed to convert validator node change: {}",
-                            e
-                        ))
-                    })?;
+                let mut node_changes_converted = Vec::with_capacity(node_changes.len());
+                for change in node_changes {
+                    match TryInto::try_into(change) {
+                        Ok(c) => node_changes_converted.push(c),
+                        Err(e) => {
+                            warn!(target: LOG_TARGET, "Invalid validator node change from base node: {e}");
+                        }
+                    }
+                }
+                let node_changes = node_changes_converted;
integration_tests/tests/steps/validator_node.rs (2)

191-194: Replace unwrap() on MemoField with expect for clearer failures.

Apply:

-            payment_id: MemoField::new_open_from_string("Register by cucumber", TxType::ValidatorNodeRegistration)
-                .unwrap()
-                .to_bytes(),
+            payment_id: MemoField::new_open_from_string("Register by cucumber", TxType::ValidatorNodeRegistration)
+                .expect("failed to encode MemoField for VN registration")
+                .to_bytes(),

391-398: Tighten error messages around GetState.
Use expect(...) instead of unwrap() to include context if the RPC fails; keep optional() handling as-is.

Apply:

-            .optional()
-            .unwrap()
+            .optional()
+            .expect("get_state RPC failed for substate address")

Also applies to: 405-414

applications/tari_walletd/src/main.rs (1)

62-64: Avoid keeping the override password as a plain String in config.

Consider secrecy::SecretString (and zeroize on drop) to reduce exposure in logs/mem dumps.

If you want, I can sketch the config/type changes across the SDK/config to propagate SecretString.

integration_tests/tests/steps/wallet.rs (1)

47-53: Minor consistency: use the helper that avoids alloc.

MemoField::open_from_string("Burn", TxType::Burn) keeps things consistent with other steps and avoids a temporary Vec.

-            payment_id: MemoField::new_open("Burn".as_bytes().to_vec(), TxType::Burn)
-                .unwrap()
-                .to_bytes(),
+            payment_id: MemoField::open_from_string("Burn", TxType::Burn).to_bytes(),
integration_tests/tests/steps/wallet_daemon.rs (2)

54-70: Track the TODO on negative-path validation.

Current comment notes an upstream limitation. Consider marking with an issue so it doesn’t get lost.

I can open a follow-up issue describing the missing VN-behaviour assertion and propose a guard to detect the specific failure mode.


177-191: Fix string interpolation in cucumber log.

The braces won’t interpolate; use format! (or log the hex if preferred).

-    let public_key = nonce.public_key;
-    cucumber_log("Burning funds using claim key {public_key}");
+    let public_key = nonce.public_key;
+    cucumber_log(format!("Burning funds using claim key {:?}", public_key));
integration_tests/src/lib.rs (3)

105-137: Init path looks correct; tighten panic messages

Prefer expect() with context over unwrap() for quicker triage in flaky CI.

-        )
-        .unwrap();
+        )
+        .expect("failed to construct default_payment_address from wallet_private_key");
...
-            key_manager: create_memory_db_key_manager().await.unwrap(),
+            key_manager: create_memory_db_key_manager()
+                .await
+                .expect("failed to create in-memory key manager"),

166-169: Improve panic message for missing scenario name

Clearer guidance when misused.

-        self.current_scenario_name.as_deref().expect("No current scenario")
+        self.current_scenario_name
+            .as_deref()
+            .expect("current_scenario_name is None; ensure it is set before spawning processes that use it")

328-330: Debug label mismatch: “addresses” → “substate_ids”

Minor clarity fix.

-            .field("claim_proofs", &self.claim_proofs.keys())
-            .field("addresses", &self.substate_ids.keys())
+            .field("claim_proofs", &self.claim_proofs.keys())
+            .field("substate_ids", &self.substate_ids.keys())
integration_tests/src/wallet_daemon.rs (2)

145-159: claim_burn helper — consider fee configurability

Hardcoded max_fee=5000 may cause intermittent failures if fees rise. Allow an optional parameter with a sensible default.

-    pub async fn claim_burn(
-        &self,
-        account_name: &str,
-        claim_proof: ExtClaimBurnProof,
-    ) -> Result<ClaimBurnResponse, WalletDaemonClientError> {
+    pub async fn claim_burn(
+        &self,
+        account_name: &str,
+        claim_proof: ExtClaimBurnProof,
+        max_fee: Option<u64>,
+    ) -> Result<ClaimBurnResponse, WalletDaemonClientError> {
         let mut client = self.get_authed_client().await;
 
         let req = ClaimBurnRequest {
             account: ComponentAddressOrName::Name(account_name.into()),
             claim_proof,
-            max_fee: Some(5000),
+            max_fee: max_fee.or(Some(5_000)),
         };
 
         client.claim_burn(req).await
     }

161-170: wait_for_transaction_result — consider timeout param

To reduce fixed waits in features, expose timeout_secs as a parameter (default 30).

-    pub async fn wait_for_transaction_result(&self, tx_id: TransactionId) -> TransactionWaitResultResponse {
+    pub async fn wait_for_transaction_result(
+        &self,
+        tx_id: TransactionId,
+        timeout_secs: Option<u64>,
+    ) -> TransactionWaitResultResponse {
         let mut client = self.get_authed_client().await;
         client
             .wait_transaction_result(TransactionWaitResultRequest {
                 transaction_id: tx_id,
-                timeout_secs: Some(30),
+                timeout_secs: timeout_secs.or(Some(30)),
             })
             .await
             .unwrap()
     }
crates/wallet/sdk/src/apis/key_manager.rs (3)

87-91: Tidy: simplify error mapping noise.

You repeatedly do .map_err(key_manager::error::KeyManagerServiceError::from)?. Prefer .map_err(Into::into)? (or let ? work directly if you add a From impl to KeyManagerApiError), reducing verbosity and coupling.

Example changes:

-                .map_err(key_manager::error::KeyManagerServiceError::from)?;
+                .map_err(Into::into)?;

Repeat similarly in the other occurrences.

Also applies to: 103-110, 152-160, 210-214


208-214: Avoid write-side effects during brute-force search.

search_for_key_within_range currently calls get_or_create_key_manager, which can create a DB row as a side effect. For a read-only search, construct a non-mutating manager instead.

Apply:

-        let km = self.get_or_create_key_manager(branch)?;
+        let km = self.get_key_manager(branch, 0);

251-253: Minor: avoid cloning CipherSeed if not necessary.

If TariKeyManager::from supports borrowing the seed, prefer that to avoid repeated clones on hot paths. Otherwise, consider caching managers per branch if derivations are frequent.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ac72f65 and 716a3c3.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (67)
  • .gitignore (1 hunks)
  • Cargo.toml (4 hunks)
  • README.md (1 hunks)
  • applications/tari_indexer/src/network_client.rs (2 hunks)
  • applications/tari_swarm_daemon/Cargo.toml (1 hunks)
  • applications/tari_swarm_daemon/src/layer_one_transactions/submitter.rs (3 hunks)
  • applications/tari_swarm_daemon/src/process_definitions/minotari_node.rs (0 hunks)
  • applications/tari_swarm_daemon/src/process_definitions/minotari_wallet.rs (1 hunks)
  • applications/tari_swarm_daemon/src/process_manager/manager.rs (1 hunks)
  • applications/tari_swarm_daemon/src/process_manager/processes/minotari_wallet.rs (2 hunks)
  • applications/tari_swarm_daemon/src/process_manager/processes/wallet_daemon.rs (1 hunks)
  • applications/tari_validator_node/Cargo.toml (1 hunks)
  • applications/tari_validator_node/src/json_rpc/handlers.rs (1 hunks)
  • applications/tari_validator_node/src/lib.rs (2 hunks)
  • applications/tari_walletd/Cargo.toml (2 hunks)
  • applications/tari_walletd/src/cli.rs (3 hunks)
  • applications/tari_walletd/src/config.rs (2 hunks)
  • applications/tari_walletd/src/lib.rs (3 hunks)
  • applications/tari_walletd/src/main.rs (5 hunks)
  • applications/tari_walletd/src/services/recovery_service.rs (2 hunks)
  • applications/tari_watcher/Cargo.toml (1 hunks)
  • applications/tari_watcher/src/minotari.rs (3 hunks)
  • clients/base_node_client/Cargo.toml (1 hunks)
  • clients/base_node_client/src/grpc.rs (3 hunks)
  • clients/base_node_client/src/traits.rs (1 hunks)
  • clients/base_node_client/src/types.rs (1 hunks)
  • crates/epoch_manager/Cargo.toml (2 hunks)
  • crates/epoch_manager/src/epoch_event_oracle/event.rs (2 hunks)
  • crates/epoch_oracles/Cargo.toml (2 hunks)
  • crates/epoch_oracles/src/base_layer/mod.rs (6 hunks)
  • crates/wallet/sdk/Cargo.toml (1 hunks)
  • crates/wallet/sdk/src/apis/accounts.rs (1 hunks)
  • crates/wallet/sdk/src/apis/confidential_outputs.rs (2 hunks)
  • crates/wallet/sdk/src/apis/key_manager.rs (10 hunks)
  • crates/wallet/sdk/src/lib.rs (1 hunks)
  • crates/wallet/sdk/src/models/key.rs (2 hunks)
  • crates/wallet/sdk/src/sdk.rs (4 hunks)
  • integration_tests/Cargo.toml (2 hunks)
  • integration_tests/src/base_node.rs (3 hunks)
  • integration_tests/src/indexer.rs (4 hunks)
  • integration_tests/src/lib.rs (7 hunks)
  • integration_tests/src/miner.rs (2 hunks)
  • integration_tests/src/templates/basic_nft/src/lib.rs (3 hunks)
  • integration_tests/src/templates/faucet/src/lib.rs (1 hunks)
  • integration_tests/src/util.rs (1 hunks)
  • integration_tests/src/validator_node.rs (5 hunks)
  • integration_tests/src/wallet.rs (6 hunks)
  • integration_tests/src/wallet_daemon.rs (5 hunks)
  • integration_tests/src/wallet_daemon_cli.rs (2 hunks)
  • integration_tests/tests/cucumber.rs (1 hunks)
  • integration_tests/tests/features/claim_burn.feature (1 hunks)
  • integration_tests/tests/features/claim_fees.feature (4 hunks)
  • integration_tests/tests/features/committee.feature (1 hunks)
  • integration_tests/tests/features/epoch_change.feature (2 hunks)
  • integration_tests/tests/features/eviction.feature (1 hunks)
  • integration_tests/tests/features/state_sync.feature (2 hunks)
  • integration_tests/tests/features/substates.feature (1 hunks)
  • integration_tests/tests/features/transfer.feature (5 hunks)
  • integration_tests/tests/features/wallet_daemon.feature (2 hunks)
  • integration_tests/tests/log4rs/cucumber.yml (2 hunks)
  • integration_tests/tests/steps/common.rs (1 hunks)
  • integration_tests/tests/steps/indexer.rs (2 hunks)
  • integration_tests/tests/steps/miner.rs (1 hunks)
  • integration_tests/tests/steps/network.rs (2 hunks)
  • integration_tests/tests/steps/validator_node.rs (10 hunks)
  • integration_tests/tests/steps/wallet.rs (3 hunks)
  • integration_tests/tests/steps/wallet_daemon.rs (6 hunks)
💤 Files with no reviewable changes (1)
  • applications/tari_swarm_daemon/src/process_definitions/minotari_node.rs
🧰 Additional context used
🧬 Code graph analysis (18)
applications/tari_swarm_daemon/src/process_manager/processes/wallet_daemon.rs (1)
clients/javascript/wallet_daemon_client/src/index.ts (1)
  • WalletDaemonClient (102-357)
integration_tests/src/base_node.rs (1)
integration_tests/src/util.rs (1)
  • cucumber_log (12-15)
integration_tests/src/templates/faucet/src/lib.rs (1)
crates/template_lib/src/auth/access_rules.rs (1)
  • allow_all (137-142)
crates/epoch_manager/src/epoch_event_oracle/event.rs (1)
crates/common_types/src/substate_address.rs (1)
  • from_hash_and_version (97-105)
integration_tests/tests/steps/common.rs (2)
integration_tests/src/util.rs (1)
  • cucumber_log (12-15)
crates/template_lib/src/models/layer_one_commitment.rs (1)
  • from_commitment (34-36)
integration_tests/src/templates/basic_nft/src/lib.rs (1)
crates/template_lib/src/auth/access_rules.rs (1)
  • allow_all (137-142)
crates/wallet/sdk/src/apis/accounts.rs (4)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/ComponentAddress.ts (1)
  • ComponentAddress (6-6)
crates/engine_types/src/component.rs (1)
  • derive_component_address_from_public_key (43-53)
bindings/src/helpers/consts.ts (1)
  • ACCOUNT_TEMPLATE_ADDRESS (6-6)
integration_tests/tests/steps/indexer.rs (2)
integration_tests/tests/cucumber.rs (3)
  • world (316-316)
  • world (523-523)
  • world (674-683)
integration_tests/tests/steps/validator_node.rs (2)
  • world (139-148)
  • world (470-474)
integration_tests/tests/steps/network.rs (11)
integration_tests/src/indexer.rs (1)
  • spawn_indexer (162-235)
integration_tests/src/miner.rs (1)
  • register_miner_process (52-59)
integration_tests/src/util.rs (1)
  • cucumber_log (12-15)
integration_tests/src/validator_node.rs (1)
  • spawn_validator_node (118-218)
integration_tests/src/wallet.rs (1)
  • spawn_wallet (115-236)
integration_tests/src/wallet_daemon.rs (1)
  • spawn_wallet_daemon (69-111)
integration_tests/src/base_node.rs (2)
  • world (78-82)
  • spawn_base_node (61-170)
integration_tests/tests/steps/validator_node.rs (4)
  • world (139-148)
  • world (470-474)
  • send_vn_registration (169-208)
  • assert_vn_is_registered (285-318)
integration_tests/tests/steps/miner.rs (1)
  • miner_mines_new_blocks (15-44)
integration_tests/tests/steps/wallet.rs (1)
  • check_balance (78-117)
integration_tests/tests/steps/indexer.rs (1)
  • indexer_has_scanned_to_at_least_height (50-76)
integration_tests/src/indexer.rs (4)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
applications/tari_validator_node/src/json_rpc/handlers.rs (1)
  • add_peer (648-696)
applications/tari_indexer/src/json_rpc/handlers.rs (1)
  • add_peer (174-221)
clients/tari_indexer_client/src/json_rpc_client.rs (1)
  • add_peer (83-85)
clients/base_node_client/src/traits.rs (5)
bindings/src/types/validator-node-client/ValidatorNodeChange.ts (1)
  • ValidatorNodeChange (9-18)
bindings/src/types/BlockHeader.ts (1)
  • BlockHeader (9-73)
bindings/src/types/Epoch.ts (1)
  • Epoch (3-3)
bindings/src/types/SubstateAddress.ts (1)
  • SubstateAddress (3-3)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
integration_tests/tests/steps/wallet.rs (8)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
  • KeyBranch (3-3)
bindings/src/types/PedersenCommitmentBytes.ts (1)
  • PedersenCommitmentBytes (6-6)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/Scalar32Bytes.ts (1)
  • Scalar32Bytes (3-3)
bindings/src/types/CommitmentSignatureBytes.ts (1)
  • CommitmentSignatureBytes (5-5)
bindings/src/types/RangeProofBytes.ts (1)
  • RangeProofBytes (9-9)
bindings/src/types/wallet-daemon-client/ClaimBurnProof.ts (1)
  • ClaimBurnProof (7-12)
bindings/src/types/wallet-daemon-client/ExtClaimBurnProof.ts (1)
  • ExtClaimBurnProof (4-4)
integration_tests/tests/steps/wallet_daemon.rs (5)
integration_tests/src/util.rs (1)
  • cucumber_log (12-15)
integration_tests/src/wallet_daemon.rs (1)
  • claim_burn (145-159)
integration_tests/src/wallet_daemon_cli.rs (2)
  • claim_burn (81-109)
  • get_auth_wallet_daemon_client (904-906)
clients/wallet_daemon_client/src/lib.rs (1)
  • claim_burn (342-347)
crates/template_lib_types/src/crypto/commitment_signature.rs (1)
  • from_bytes (39-54)
integration_tests/src/lib.rs (4)
bindings/src/types/SubstateId.ts (1)
  • SubstateId (15-24)
bindings/src/types/SubstateRequirement.ts (1)
  • SubstateRequirement (3-3)
bindings/src/types/RistrettoPublicKeyBytes.ts (1)
  • RistrettoPublicKeyBytes (6-6)
bindings/src/types/wallet-daemon-client/ExtClaimBurnProof.ts (1)
  • ExtClaimBurnProof (4-4)
clients/base_node_client/src/grpc.rs (1)
bindings/src/types/validator-node-client/ValidatorNodeChange.ts (1)
  • ValidatorNodeChange (9-18)
applications/tari_walletd/src/main.rs (1)
applications/tari_walletd/src/lib.rs (3)
  • init_wallet_store (166-170)
  • initialize_wallet_sdk (172-189)
  • run_tari_ootle_walletd (65-164)
integration_tests/src/wallet_daemon.rs (5)
applications/tari_walletd/src/lib.rs (1)
  • run_tari_ootle_walletd (65-164)
integration_tests/src/logging.rs (1)
  • get_base_dir_for_scenario (32-42)
clients/javascript/wallet_daemon_client/src/index.ts (1)
  • WalletDaemonClient (102-357)
integration_tests/src/wallet_daemon_cli.rs (1)
  • claim_burn (81-109)
clients/wallet_daemon_client/src/lib.rs (1)
  • claim_burn (342-347)
integration_tests/tests/steps/validator_node.rs (3)
integration_tests/src/util.rs (1)
  • cucumber_log (12-15)
integration_tests/tests/cucumber.rs (3)
  • world (316-316)
  • world (523-523)
  • world (674-683)
crates/common_types/src/substate_address.rs (1)
  • from_substate_id (40-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: clippy
  • GitHub Check: check nightly
  • GitHub Check: test
  • GitHub Check: check stable
  • GitHub Check: fmt

Comment thread .gitignore
# moon
.moon/cache
.moon/docker
./cucumber-output-junit.xml No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix: pattern won’t match; use a root-anchored ignore

.gitignore doesn’t treat "./" specially. Use a leading slash to anchor to repo root so the file is actually ignored.

-./cucumber-output-junit.xml
+/cucumber-output-junit.xml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
./cucumber-output-junit.xml
/cucumber-output-junit.xml
🤖 Prompt for AI Agents
In .gitignore around line 65, the pattern "./cucumber-output-junit.xml" won't
match because .gitignore doesn't treat "./" specially; replace it with a
root-anchored pattern "/cucumber-output-junit.xml" so the file at the repo root
is actually ignored (remove the "./" and add the leading slash).

Comment on lines +82 to 83
pub override_keyring_password: Option<SafePassword>,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent leaking override_keyring_password via serialization/logging

Storing a password in config is risky; this field currently serializes (struct derives Serialize). Ensure it never gets emitted to logs or “dump config” endpoints.

Apply:

-    pub override_keyring_password: Option<SafePassword>,
+    /// DANGER: Dev/test-only override. Do not persist or log this value.
+    /// This field is never serialized to avoid accidental disclosure.
+    #[serde(skip_serializing)]
+    pub override_keyring_password: Option<SafePassword>,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub override_keyring_password: Option<SafePassword>,
}
/// DANGER: Dev/test-only override. Do not persist or log this value.
/// This field is never serialized to avoid accidental disclosure.
#[serde(skip_serializing)]
pub override_keyring_password: Option<SafePassword>,
}
🤖 Prompt for AI Agents
In applications/tari_walletd/src/config.rs around lines 82-83, the
override_keyring_password field is currently serialized and can leak via logs or
config dumps; mark the field to never be serialized and prevent it showing up in
debug output by adding serde attributes (e.g. #[serde(skip_serializing,
skip_deserializing)] or #[serde(skip)]) to exclude it from any Serde-based dumps
and either implement a custom Debug for the struct that omits this field or
annotate it to be skipped by your debug/redaction utility (e.g. #[debug(skip)]
or use the crate-specific redaction attribute) so it is never emitted in logs or
endpoints.

Comment on lines 172 to 179
pub fn initialize_wallet_sdk(
cli: &Cli,
config: &ApplicationConfig,
store: SqliteWalletStore,
) -> anyhow::Result<WalletSdk<SqliteWalletStore, IndexerJsonRpcNetworkInterface>> {
let sdk_config = WalletSdkConfig {
network: config.ootle_wallet_daemon.network,
override_keyring_password: cli.override_keyring_password.clone(),
override_keyring_password: config.ootle_wallet_daemon.override_keyring_password.clone(),
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Don’t source keyring passwords from config; prefer env with redaction.
Reading override_keyring_password from config risks plaintext leakage. At minimum, allow an env override and avoid logging it.

Apply:

     let sdk_config = WalletSdkConfig {
         network: config.ootle_wallet_daemon.network,
-        override_keyring_password: config.ootle_wallet_daemon.override_keyring_password.clone(),
+        override_keyring_password: std::env::var("TARI_WALLETD_KEYRING_PASSWORD")
+            .ok()
+            .or_else(|| config.ootle_wallet_daemon.override_keyring_password.clone()),
     };
🤖 Prompt for AI Agents
In applications/tari_walletd/src/lib.rs around lines 172 to 179, the code
currently reads override_keyring_password directly from config which risks
plaintext leakage; change it to prefer a secret provided via environment (e.g.
OOTLE_KEYRING_PASSWORD) and only fall back to the config value if the env var is
unset; treat the password as an Option (or a secret wrapper) so it can be
redacted from logs and never printed; update WalletSdkConfig construction to use
that env-first value and ensure any logging or error messages never include the
password content.

Comment on lines +68 to 75
Some(Subcommand::CreateAccount {
key_index,
set_active,
output_path,
}) => {
let wallet_store = init_wallet_store(&config)?;
let mut sdk = initialize_wallet_sdk(&cli, &config, wallet_store)?;
let mut sdk = initialize_wallet_sdk(&config, wallet_store)?;
sdk.initialize_cipher_seed(cli.wallet_restore.seed_words.as_ref())?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

JSON serialization likely fails for RistrettoPublicKey; also avoid hardcoding account name.

  • RistrettoPublicKey usually doesn’t implement Serialize. Emit bytes (or hex) instead.
  • Hardcoding Some("Fee") for a generic “CreateAccount” command is surprising; prefer None or a CLI-provided label.

Apply these diffs:

-            sdk.accounts_api()
-                .add_account(Some("Fee"), &account_addr, secret.key_index, false, true)?;
+            sdk.accounts_api()
+                .add_account(None, &account_addr, secret.key_index, false, true)?;
-            let json = json!({
-                "address": account_addr,
-                "public_key": public_key,
-                "key_index": secret.key_index,
-            });
+            let json = json!({
+                "address": account_addr.to_string(),
+                "public_key": public_key.to_byte_type(),
+                "key_index": secret.key_index,
+            });

Please run a local cargo check -p tari_walletd to ensure serde impls are satisfied for the address type, or switch that to .to_string() as shown.

Also applies to: 82-89, 95-97


🏁 Script executed:

#!/bin/bash
set -e

echo "1. Searching for RistrettoPublicKey occurrences and potential Serialize impls"
rg -n 'RistrettoPublicKey' -C3 || true
rg -nP 'impl\s+.*serde::Serialize\s+for\s+RistrettoPublicKey' -C3 || true

echo "2. Searching for available byte‐conversion methods on RistrettoPublicKey"
rg -n 'to_bytes' -C3 || true
rg -n 'to_vec' -C3 || true
rg -n 'to_byte_type' -C3 || true

echo "3. Inspecting add_account signature in the SDK"
rg -nP '\.add_account\(' -C3 || true

Length of output: 268243


Ensure JSON fields are serializable and remove hardcoded account name

  • Replace
    sdk.accounts_api()
        .add_account(Some("Fee"), &account_addr, secret.key_index, false, true)?;
    with
    sdk.accounts_api()
        .add_account(None, &account_addr, secret.key_index, false, true)?;
  • Replace
    let json = json!({
        "address": account_addr,
        "public_key": public_key,
        "key_index": secret.key_index,
    });
    with
    let json = json!({
        "address": account_addr.to_string(),
        "public_key": public_key.to_byte_type(),
        "key_index": secret.key_index,
    });

Also apply the same changes at lines 82–89 and 95–97.

🤖 Prompt for AI Agents
In applications/tari_walletd/src/main.rs around lines 68–75 (and also apply the
same changes at lines 82–89 and 95–97): the review asks to remove the hardcoded
account name and ensure JSON fields are serializable; replace the call that
passes Some("Fee") to add_account with None, and when building the JSON object
convert address and public_key to serializable types by calling to_string() on
the address and using the public key's serialization method (e.g.
to_byte_type()) for public_key, leaving key_index as-is.

Comment thread Cargo.toml
Comment on lines 125 to +147
# external minotari/tari dependencies
minotari_app_grpc = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_app_utilities = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_console_wallet = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_node = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_node_grpc_client = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_wallet = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_wallet_grpc_client = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_common = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_common_types = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_common_sqlite = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_hashing = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_sidechain = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_jellyfish = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
minotari_app_grpc = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_app_utilities = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_console_wallet = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_node = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_node_grpc_client = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_wallet = { git = "https://github.com/tari-project/tari.git", branch = "development" }
minotari_wallet_grpc_client = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common_types = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_common_sqlite = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_hashing = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_sidechain = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_jellyfish = { git = "https://github.com/tari-project/tari.git", branch = "development" }

# avoid including default features so each crate can choose which ones to import
tari_core = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1", default-features = false }
tari_key_manager = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_metrics = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_mmr = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_p2p = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_shutdown = { git = "https://github.com/tari-project/tari.git", tag = "v4.9.0-pre.1" }
tari_transaction_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_node_components = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_transaction_key_manager = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_metrics = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_mmr = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_p2p = { git = "https://github.com/tari-project/tari.git", branch = "development" }
tari_shutdown = { git = "https://github.com/tari-project/tari.git", branch = "development" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Pin git dependencies to a release tag or commit (avoid tracking development).

Tracking upstream branch = "development" is non-reproducible and risky for a breaking chore to 5.0.0. Please pin to the 5.0.0 tag (or a specific commit) across these deps for deterministic builds.

Example diff for one dep (repeat for all in 125–147):

-minotari_node = { git = "https://github.com/tari-project/tari.git", branch = "development" }
+minotari_node = { git = "https://github.com/tari-project/tari.git", tag = "v5.0.0" }

Quick check to list all branch-pinned deps:


🏁 Script executed:

#!/bin/bash
rg -nP '^\s*[\w-]+\s*=\s*\{[^}]*\bgit\s*=.*\bbranch\s*=\s*"(development|main|master)"' Cargo.toml

Length of output: 2123


Pin Tari git dependencies to v5.0.0 tag
Replace branch = "development" with tag = "v5.0.0" for all Tari dependencies in Cargo.toml (lines 126–147) to ensure deterministic, reproducible builds.

🤖 Prompt for AI Agents
In Cargo.toml around lines 125 to 147, the Tari git dependencies currently use
branch = "development" which yields non-deterministic builds; update each Tari
dependency entry to use tag = "v5.0.0" instead of branch = "development" so the
dependencies are pinned to the v5.0.0 tag for reproducible builds (i.e., replace
each occurrence of branch = "development" with tag = "v5.0.0" for all
Tari-related dependencies listed).

Comment thread integration_tests/src/lib.rs
Comment thread integration_tests/src/lib.rs
Comment on lines +27 to 29
Then VN has scanned to at least height 17
And indexer IDX has scanned to at least height 17
Then the validator node VN is listed as registered

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Good change to “at least height” to reduce test flakiness.

Ensure step definitions support the new phrasing everywhere:

Also applies to: 40-41, 72-74, 86-86


🏁 Script executed:

#!/bin/bash
rg -n 'scanned to height ' integration_tests/tests/features
rg -n 'scanned to at least height ' integration_tests

Length of output: 4102


Update remaining “scanned to height” steps
integration_tests/tests/features/eviction.feature lines 35, 56 and 59 still use “scanned to height {int}”; replace each with “scanned to at least height {int}” to match the updated step definitions.

🤖 Prompt for AI Agents
integration_tests/tests/features/eviction.feature around lines 35, 56, and 59:
update the step text occurrences that read "scanned to height {int}" to "scanned
to at least height {int}" so they match the updated step definitions; ensure you
change each exact step line (including spacing/casing) to the new phrase so the
feature uses the updated matcher.

Comment thread integration_tests/tests/log4rs/cucumber.yml
Comment thread integration_tests/tests/steps/network.rs
@sdbondi
sdbondi merged commit bee07d3 into tari-project:development Sep 1, 2025
10 of 12 checks passed
@sdbondi
sdbondi deleted the upgrade-tari-5.0.0 branch September 1, 2025 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants