Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: base node qr code #320

Merged
merged 6 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 11 additions & 10 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,27 @@ version = "1.6.0"
edition = "2021"

[dependencies]
tari_common_types = { git = "https://github.com/tari-project/tari", tag = "v1.0.0-rc.2" }
tari_launchpad_protocol = { path = "../libs/protocol" }
tari_sdm = { path = "../libs/sdm" }
tari_sdm_assets = { path = "../libs/sdm-assets" }
tari_sdm_launchpad = { path = "../libs/sdm-launchpad" }
tari_utilities = "0.7.0"

anyhow = "1.0.71"
async-trait = "0.1.68"
byte-unit = "5.1.3"
crossterm = "0.26.1"
derive_more = "0.99.17"
derive_setters = "0.1.0"
log = "0.4.17"
log4rs = "1.2.0"
rust_decimal = "1.29.1"
qrcode = { version = "0.13" }
ratatui = "0.23.0"
strum = { version = "0.24.1", features = ["derive"] }
tact = { path = "../libs/tact" }
thiserror = "1.0.40"
tokio = "1.28.1"
ratatui = "0.23.0"
byte-unit = "5.1.3"

derive_setters = "0.1.0"

tari_launchpad_protocol = { path = "../libs/protocol" }
tari_sdm_assets = { path = "../libs/sdm-assets" }
tari_sdm = { path = "../libs/sdm" }
tari_sdm_launchpad = { path = "../libs/sdm-launchpad" }

[features]
default = []
9 changes: 5 additions & 4 deletions cli/src/component/normal/base_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use ratatui::{
prelude::*,
widgets::Padding,
};
use tari_common_types::types::PublicKey;
use tari_utilities::ByteArray;

use crate::{
component::{
Expand Down Expand Up @@ -37,10 +39,9 @@ impl BaseNodeStatus {
let top_line = Line::from(vec![sync_state, chain_height, peer_count]);
let public_key = node_status
.identity
.as_ref()
.cloned()
.map(|id| (id.public_key))
.unwrap_or_else(|| ("-".into()));
.clone()
.map(|id| PublicKey::from_vec(&id.public_key).map_or("-".to_string(), |k| k.to_string()))
.unwrap_or_else(|| "-".into());
let mid_line = Line::from(format!("Public key: {public_key}"));
Text::from(vec![top_line, mid_line])
}
Expand Down
15 changes: 14 additions & 1 deletion cli/src/component/settings/base_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
};

use crate::component::widgets::qr_code::QrCodePreview;
use crate::{
component::{
elements::block_with_title,
Expand All @@ -45,13 +46,17 @@ static ROOT_FOLDER: Focus = focus_id!();
pub struct BaseNodeSettings {
expert_sep: Separator,
root_folder: LabeledInput,
qr_sep: Separator,
qr_code: QrCodePreview,
}

impl BaseNodeSettings {
pub fn new() -> Self {
Self {
expert_sep: Separator::new("Expert", []),
root_folder: LabeledInput::new("Root folder", ROOT_FOLDER),
qr_sep: Separator::new("QR Code", []),
qr_code: QrCodePreview::new(),
}
}
}
Expand Down Expand Up @@ -94,7 +99,13 @@ impl<B: Backend> Component<B> for BaseNodeSettings {
let block = block_with_title(Some("BaseNode Settings"), state.focus_on == BASE_NODE_SETTINGS);
let inner_rect = block.inner(rect);
f.render_widget(block, rect);
let constraints = [Constraint::Length(1), Constraint::Length(3), Constraint::Min(0)];
let constraints = [
Constraint::Length(1),
Constraint::Length(3),
Constraint::Length(1),
Constraint::default(),
Constraint::Min(0),
];
let chunks = Layout::default()
.vertical_margin(1)
.horizontal_margin(3)
Expand All @@ -103,5 +114,7 @@ impl<B: Backend> Component<B> for BaseNodeSettings {
.split(inner_rect);
self.expert_sep.draw(f, chunks[0], state);
self.root_folder.draw(f, chunks[1], state);
self.qr_sep.draw(f, chunks[2], state);
self.qr_code.draw(f, chunks[3], state);
}
}
2 changes: 2 additions & 0 deletions cli/src/component/widgets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ pub mod docker_detect;
mod label;
mod labeled_input;
pub mod popup;
pub mod qr_code;
mod separator;
pub mod status_line;

pub use label::Label;
pub use labeled_input::LabeledInput;
pub use separator::Separator;
84 changes: 84 additions & 0 deletions cli/src/component/widgets/qr_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2023. The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use qrcode::render::unicode;
use qrcode::QrCode;
use ratatui::widgets::Block;
use ratatui::{backend::Backend, layout::Rect, widgets::Paragraph};
use tari_common_types::types::PublicKey;
use tari_launchpad_protocol::settings::TariNetwork;
use tari_launchpad_protocol::wallet::InvalidPublicKey;
use tari_utilities::hex::Hex;
use tari_utilities::ByteArray;

use crate::{
component::{Component, ComponentEvent, Frame, Input},
state::AppState,
};

pub struct QrCodePreview {}

impl QrCodePreview {
pub fn new() -> Self {
Self {}
}
}

impl Input for QrCodePreview {
type Output = ();

fn on_event(&mut self, _event: ComponentEvent, _state: &mut AppState) -> Option<Self::Output> {
None
}
}

impl<B: Backend> Component<B> for QrCodePreview {
type State = AppState;

fn draw(&self, f: &mut Frame<B>, rect: Rect, state: &Self::State) {
let node_status = &state.state.node;
if let (_, Some(identity)) = (
state.state.config.session.is_base_node_active(),
node_status.identity.clone(),
) {
let network = if let Some(settings) = state.state.config.settings.as_ref() {
settings.saved_settings.tari_network
} else {
TariNetwork::default()
};

let public_key =
match PublicKey::from_vec(&identity.public_key).map_err(|e| InvalidPublicKey(e.to_string())) {
Ok(public_key) => public_key,
Err(e) => {
log::warn!("Couldn't convert public key: {}", e);
return;
},
};

let peer = format!("{}::{}", public_key, identity.public_addresses[0]);
let qr_link = format!(
"tari://{}/base_nodes/add?name={}&peer={}",
network.lower_case(),
identity.node_id.to_hex(),
peer
);
if let Ok(code) = QrCode::new(qr_link.clone()) {
let image = code
.render::<unicode::Dense1x2>()
.dark_color(unicode::Dense1x2::Dark)
.light_color(unicode::Dense1x2::Light)
.max_dimensions(40, 20)
.module_dimensions(1, 1)
.build()
.lines()
.skip(1)
.fold("".to_string(), |acc, l| format!("{}{}\n", acc, l));

let qr_code = Paragraph::new(image).block(Block::default());

f.render_widget(qr_code, rect);
}
}
}
}
6 changes: 3 additions & 3 deletions libs/protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ tari_common_types = { git = "https://github.com/tari-project/tari", tag = "v1.0.
tari_utilities = "0.7.0"

byte-unit = { version = "5.1.3", features = ["serde"] }
chrono = { version = "0.4.26", features = ["serde"] }
derive_more = "0.99.17"
log = "0.4.20"
serde = "1"
serde_repr = "0.1.16"
strum = { version = "0.25.0", features = ["derive"] }
thiserror = "1.0.44"
chrono = { version = "0.4.26", features = ["serde"] }
serde_repr = "0.1.16"
toml = { version = "0.8.8", features = [] }
log = "0.4.20"
28 changes: 21 additions & 7 deletions libs/protocol/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,37 @@ use minotari_node_grpc_client::grpc::NodeIdentity;
use serde::{Deserialize, Serialize};
use tari_common_types::{emoji::EmojiId, types::PublicKey};
use tari_utilities::byte_array::ByteArray;
use tari_utilities::hex::Hex;

use crate::wallet::InvalidPublicKey;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BaseNodeAddress {
pub public_key: String,
#[serde(rename_all = "camelCase")]
pub struct BaseNodeIdentity {
pub public_key: Vec<u8>,
pub public_addresses: Vec<String>,
pub node_id: Vec<u8>,
pub emoji_id: String,
}

impl TryFrom<NodeIdentity> for BaseNodeAddress {
impl BaseNodeIdentity {
/// Provide the base node connection string. It is of the form
/// "0eefb45a4de9484eca74846a4f47d2c8d38e76be1fec63b0112bd00d297c0928::/ip4/13.40.98.39/tcp/18189"
pub fn connection_string(&self) -> String {
format!("{}::/dns4/base_node/tcp/18189", self.public_key.to_hex())
}
}

impl TryFrom<NodeIdentity> for BaseNodeIdentity {
type Error = InvalidPublicKey;

fn try_from(value: NodeIdentity) -> Result<Self, Self::Error> {
let public_key = PublicKey::from_vec(&value.public_key).map_err(|e| InvalidPublicKey(e.to_string()))?;
let emoji_id = EmojiId::from_public_key(&public_key).to_string();
Ok(BaseNodeAddress {
public_key: public_key.to_string(),
Ok(BaseNodeIdentity {
public_key: value.public_key,
public_addresses: value.public_addresses,
node_id: value.node_id,
emoji_id,
})
}
Expand All @@ -30,7 +44,7 @@ impl TryFrom<NodeIdentity> for BaseNodeAddress {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeState {
// The base node's identity
pub identity: Option<BaseNodeAddress>,
pub identity: Option<BaseNodeIdentity>,
// The sync status of the base node
pub sync_status: String,
// The number of peers connected to the base node
Expand Down Expand Up @@ -72,7 +86,7 @@ impl Default for NodeState {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NodeDelta {
SetIdentity(BaseNodeAddress),
SetIdentity(BaseNodeIdentity),
SetSyncStatus(String),
SetPeerCount(usize),
SetChainLength(u64),
Expand Down
11 changes: 4 additions & 7 deletions libs/sdm-launchpad/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,23 @@ edition = "2021"
[dependencies]
minotari_app_grpc = { git = "https://github.com/tari-project/tari", tag = "v1.0.0-rc.2" }
minotari_node_grpc_client = { git = "https://github.com/tari-project/tari", tag = "v1.0.0-rc.2" }
minotari_wallet_grpc_client = { git = "https://github.com/tari-project/tari", tag = "v1.0.0-rc.2" }
tari_common_types = { git = "https://github.com/tari-project/tari", tag = "v1.0.0-rc.2" }
tari_launchpad_protocol = { path = "../protocol" }
tari_sdm_assets = { path = "../sdm-assets" }
tari_sdm = { path = "../sdm" }
minotari_wallet_grpc_client = { git = "https://github.com/tari-project/tari", tag = "v1.0.0-rc.2" }
tari_sdm_assets = { path = "../sdm-assets" }
tari_utilities = "0.7.0"
openssl = { version = "0.10.55", features = ["vendored"] }

anyhow = "1.0.72"
async-trait = "0.1.72"
futures = "0.3.28"
chrono = "0.4.31"
log = "0.4.19"
rand = "0.8.5"
regex = "1.9.1"
serde = "=1.0.167"
serde_json = "1.0.103"
tauri = { version = "=1.2.5", features = ["api-all", "cli", "macos-private-api"], optional = true }
thiserror = "1.0.44"
tor-hash-passwd = "1.0.1"
tokio = "1.29.1"
toml = "0.8.8"
tonic = { version = "0.8.3", features = ["tls"] }
chrono = "0.4.31"
tor-hash-passwd = "1.0.1"
Loading
Loading