Skip to content

Commit

Permalink
feat: added burn feature to the console wallet (#5322)
Browse files Browse the repository at this point in the history
Description
---
Added basic functionality to enable Minotari burning on the baselayer.
Copied `serde_from` module from `tari-dan` to `tari_common_types`


Motivation and Context
---
To allow users burn Minotari to be reclaimed on the second layer (DAN).

How Has This Been Tested?
---
manually

---------

Co-authored-by: SW van Heerden <swvheerden@gmail.com>
  • Loading branch information
agubarev and SWvheerden committed May 9, 2023
1 parent 41b7d84 commit 45685b9
Show file tree
Hide file tree
Showing 26 changed files with 1,501 additions and 67 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions applications/tari_console_wallet/src/ui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::{
ui::{
components::{
base_node::BaseNode,
burn_tab::BurnTab,
contacts_tab::ContactsTab,
events_component::EventsComponent,
log_tab::LogTab,
Expand Down Expand Up @@ -88,6 +89,7 @@ impl<B: Backend> App<B> {
.add("Transactions".into(), Box::new(TransactionsTab::new()))
.add("Send".into(), Box::new(SendTab::new(&app_state)))
.add("Receive".into(), Box::new(ReceiveTab::new()))
.add("Burn".into(), Box::new(BurnTab::new(&app_state)))
.add("Contacts".into(), Box::new(ContactsTab::new()))
.add("Network".into(), Box::new(NetworkTab::new(base_node_selected)))
.add("Events".into(), Box::new(EventsComponent::new()))
Expand Down
691 changes: 691 additions & 0 deletions applications/tari_console_wallet/src/ui/components/burn_tab.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::{
ui::{
components::{Component, KeyHandled},
state::AppState,
ui_contact::UiContact,
widgets::{centered_rect_absolute, draw_dialog, MultiColumnList, WindowedListState},
UiContact,
MAX_WIDTH,
},
utils::formatting::display_compressed_string,
Expand Down
1 change: 1 addition & 0 deletions applications/tari_console_wallet/src/ui/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mod styles;
pub mod tabs_container;
pub mod transactions_tab;
pub use self::component::*;
pub mod burn_tab;
pub mod contacts_tab;
pub mod events_component;

Expand Down
7 changes: 5 additions & 2 deletions applications/tari_console_wallet/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ use crate::utils::crossterm_events::CrosstermEvents;
mod app;
mod components;
pub mod state;
mod ui_burnt_proof;
mod ui_contact;
mod ui_error;
mod widgets;

use std::io::{stdout, Stdout};

pub use app::*;
Expand All @@ -43,8 +45,7 @@ use crossterm::{
use log::*;
use tokio::runtime::Handle;
use tui::{backend::CrosstermBackend, Terminal};
pub use ui_contact::*;
pub use ui_error::*;
use ui_error::UiError;

use crate::utils::events::{Event, EventStream};

Expand All @@ -58,6 +59,8 @@ pub fn run(app: App<CrosstermBackend<Stdout>>) -> Result<(), ExitError> {
app.app_state.refresh_transaction_state().await?;
trace!(target: LOG_TARGET, "Refreshing contacts state");
app.app_state.refresh_contacts_state().await?;
trace!(target: LOG_TARGET, "Refreshing burnt proofs state");
app.app_state.refresh_burnt_proofs_state().await?;
trace!(target: LOG_TARGET, "Refreshing connected peers state");
app.app_state.refresh_connected_peers_state().await?;
trace!(target: LOG_TARGET, "Checking connectivity");
Expand Down
129 changes: 126 additions & 3 deletions applications/tari_console_wallet/src/ui/state/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

use std::{
collections::{HashMap, VecDeque},
path::PathBuf,
sync::Arc,
time::{Duration, Instant},
};
Expand Down Expand Up @@ -73,11 +74,12 @@ use crate::{
ui::{
state::{
debouncer::BalanceEnquiryDebouncer,
tasks::{send_one_sided_transaction_task, send_transaction_task},
tasks::{send_burn_transaction_task, send_one_sided_transaction_task, send_transaction_task},
wallet_event_monitor::WalletEventMonitor,
},
UiContact,
UiError,
ui_burnt_proof::UiBurntProof,
ui_contact::UiContact,
ui_error::UiError,
},
utils::db::{CUSTOM_BASE_NODE_ADDRESS_KEY, CUSTOM_BASE_NODE_PUBLIC_KEY_KEY},
wallet_modes::PeerConfig,
Expand Down Expand Up @@ -164,6 +166,14 @@ impl AppState {
Ok(())
}

pub async fn refresh_burnt_proofs_state(&mut self) -> Result<(), UiError> {
let mut inner = self.inner.write().await;
inner.refresh_burnt_proofs_state().await?;
drop(inner);
self.update_cache().await;
Ok(())
}

pub async fn refresh_connected_peers_state(&mut self) -> Result<(), UiError> {
self.check_connectivity().await;
let mut inner = self.inner.write().await;
Expand Down Expand Up @@ -259,6 +269,22 @@ impl AppState {
Ok(())
}

pub async fn delete_burnt_proof(&mut self, proof_id: u32) -> Result<(), UiError> {
let mut inner = self.inner.write().await;

inner
.wallet
.db
.delete_burnt_proof(proof_id)
.map_err(UiError::WalletStorageError)?;

inner.refresh_burnt_proofs_state().await?;
drop(inner);
self.update_cache().await;

Ok(())
}

pub async fn send_transaction(
&mut self,
address: String,
Expand Down Expand Up @@ -360,6 +386,57 @@ impl AppState {
Ok(())
}

pub async fn send_burn_transaction(
&mut self,
burn_proof_filepath: Option<String>,
claim_public_key: Option<String>,
amount: u64,
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: u64,
message: String,
result_tx: watch::Sender<UiTransactionBurnStatus>,
) -> Result<(), UiError> {
let inner = self.inner.write().await;

let burn_proof_filepath = match burn_proof_filepath {
None => None,
Some(path) => {
let path = PathBuf::from(path);

if path.exists() {
return Err(UiError::BurntProofFileExists);
}

Some(path)
},
};

let fee_per_gram = fee_per_gram * uT;
let tx_service_handle = inner.wallet.transaction_service.clone();
let claim_public_key = match claim_public_key {
None => return Err(UiError::PublicKeyParseError),
Some(claim_public_key) => match PublicKey::from_hex(claim_public_key.as_str()) {
Ok(claim_public_key) => Some(claim_public_key),
Err(_) => return Err(UiError::PublicKeyParseError),
},
};

send_burn_transaction_task(
burn_proof_filepath,
claim_public_key,
MicroTari::from(amount),
selection_criteria,
message,
fee_per_gram,
tx_service_handle,
inner.wallet.db.clone(),
result_tx,
)
.await;

Ok(())
}

pub async fn cancel_transaction(&mut self, tx_id: TxId) -> Result<(), UiError> {
let inner = self.inner.write().await;
let mut tx_service_handle = inner.wallet.transaction_service.clone();
Expand All @@ -385,6 +462,14 @@ impl AppState {
&self.cached_data.my_identity
}

pub fn get_burnt_proofs(&self) -> &[UiBurntProof] {
self.cached_data.burnt_proofs.as_slice()
}

pub fn get_burnt_proof_by_index(&self, idx: usize) -> Option<&UiBurntProof> {
self.cached_data.burnt_proofs.get(idx)
}

pub fn get_contacts(&self) -> &[UiContact] {
self.cached_data.contacts.as_slice()
}
Expand All @@ -405,6 +490,14 @@ impl AppState {
&self.cached_data.contacts[start..end]
}

pub fn get_burnt_proofs_slice(&self, start: usize, end: usize) -> &[UiBurntProof] {
if self.cached_data.burnt_proofs.is_empty() || start >= end {
return &[];
}

&self.cached_data.burnt_proofs[start..end]
}

pub fn get_pending_txs(&self) -> &Vec<CompletedTransactionInfo> {
&self.cached_data.pending_txs
}
Expand Down Expand Up @@ -779,6 +872,27 @@ impl AppStateInner {
Ok(())
}

pub async fn refresh_burnt_proofs_state(&mut self) -> Result<(), UiError> {
// let db_burnt_proofs = self.wallet.db.get_burnt_proofs()?;
let db_burnt_proofs = self.wallet.db.fetch_burnt_proofs()?;
let mut ui_proofs: Vec<UiBurntProof> = vec![];

for proof in db_burnt_proofs {
ui_proofs.push(UiBurntProof {
id: proof.0,
reciprocal_claim_public_key: proof.1,
payload: proof.2,
burned_at: proof.3,
});
}

ui_proofs.sort_by(|a, b| a.burned_at.cmp(&b.burned_at));

self.data.burnt_proofs = ui_proofs;
self.updated = true;
Ok(())
}

pub async fn refresh_connected_peers_state(&mut self) -> Result<(), UiError> {
let connections = self.wallet.comms.connectivity().get_active_connections().await?;
let peer_manager = self.wallet.comms.peer_manager();
Expand Down Expand Up @@ -1063,6 +1177,7 @@ struct AppStateData {
confirmations: HashMap<TxId, u64>,
my_identity: MyIdentity,
contacts: Vec<UiContact>,
burnt_proofs: Vec<UiBurntProof>,
connected_peers: Vec<Peer>,
balance: Balance,
base_node_state: BaseNodeState,
Expand Down Expand Up @@ -1137,6 +1252,7 @@ impl AppStateData {
confirmations: HashMap::new(),
my_identity: identity,
contacts: Vec::new(),
burnt_proofs: vec![],
connected_peers: Vec::new(),
balance: Balance::zero(),
base_node_state: BaseNodeState::default(),
Expand Down Expand Up @@ -1171,6 +1287,13 @@ pub enum UiTransactionSendStatus {
Error(String),
}

#[derive(Clone, Debug)]
pub enum UiTransactionBurnStatus {
Initiated,
TransactionComplete((u32, String, String)),
Error(String),
}

bitflags! {
pub struct TransactionFilter: u8 {
const NONE = 0b0000_0000;
Expand Down
24 changes: 24 additions & 0 deletions applications/tari_console_wallet/src/ui/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,28 @@ mod debouncer;
mod tasks;
mod wallet_event_monitor;

use serde::{Deserialize, Serialize};
use tari_common_types::serializers;

pub use self::app_state::*;

#[derive(Serialize, Deserialize)]
pub struct CommitmentSignatureBase64 {
#[serde(with = "serializers::base64")]
pub public_nonce: Vec<u8>,
#[serde(with = "serializers::base64")]
pub u: Vec<u8>,
#[serde(with = "serializers::base64")]
pub v: Vec<u8>,
}

#[derive(Serialize, Deserialize)]
pub struct BurntProofBase64 {
#[serde(with = "serializers::base64")]
pub reciprocal_claim_public_key: Vec<u8>,
#[serde(with = "serializers::base64")]
pub commitment: Vec<u8>,
pub ownership_proof: Option<CommitmentSignatureBase64>,
#[serde(with = "serializers::base64")]
pub range_proof: Vec<u8>,
}
Loading

0 comments on commit 45685b9

Please sign in to comment.