Skip to content

Commit

Permalink
Fix stale errors in rusk-wallet
Browse files Browse the repository at this point in the history
Refine re-exports in wallet-core
  • Loading branch information
Daksh14 committed Aug 29, 2024
1 parent 965b9ce commit 643945a
Show file tree
Hide file tree
Showing 9 changed files with 381 additions and 233 deletions.
42 changes: 40 additions & 2 deletions rusk-wallet/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use std::collections::BTreeSet;
use std::path::Path;
use std::{cmp::Ordering, collections::BTreeSet};

use dusk_bytes::{DeserializableSlice, Serializable};
use rocksdb::{DBWithThreadMode, MultiThreaded, Options};
Expand Down Expand Up @@ -198,7 +198,7 @@ impl Cache {
&self,
pk: &PhoenixPublicKey,
) -> Result<Vec<(BlsScalar, NoteData)>, Error> {
let cf_name = format!("spent_{:?}", ps);
let cf_name = format!("spent_{:?}", pk);
let mut notes = vec![];

if let Some(cf) = self.db.cf_handle(&cf_name) {
Expand All @@ -225,3 +225,41 @@ pub(crate) struct NoteData {
pub height: u64,
pub note: Note,
}

impl PartialOrd for NoteData {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for NoteData {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.note.pos().cmp(other.note.pos())
}
}

impl Serializable<{ u64::SIZE + Note::SIZE }> for NoteData {
type Error = dusk_bytes::Error;
/// Converts a Note into a byte representation
fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut buf = [0u8; Self::SIZE];

buf[0..8].copy_from_slice(&self.height.to_bytes());

buf[8..].copy_from_slice(&self.note.to_bytes());

buf
}

/// Attempts to convert a byte representation of a note into a `Note`,
/// failing if the input is invalid
fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
let mut one_u64 = [0u8; 8];
one_u64.copy_from_slice(&bytes[0..8]);
let height = u64::from_bytes(&one_u64)?;

let note = Note::from_slice(&bytes[8..])?;
Ok(Self { height, note })
}
}
210 changes: 125 additions & 85 deletions rusk-wallet/src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@

mod sync;

use dusk_bytes::{DeserializableSlice, Serializable, Write};
use dusk_bytes::Serializable;
use flume::Receiver;
use flume::Sender;
use keys::derive_phoenix_pk;
use tokio::time::{sleep, Duration};
use wallet_core::prelude::*;
use wallet_core::input::{try_input_notes, Inputs};
use wallet_core::prelude::{Error as WalletCoreError, *};

use std::path::Path;
use std::sync::{Arc, Mutex};
Expand All @@ -21,10 +20,13 @@ use self::sync::sync_db;
use super::block::Block;
use super::cache::Cache;

use crate::cache::NoteData;
use crate::rusk::{RuskHttpClient, RuskRequest};
use crate::store::SyncStore;
use crate::Error;

pub(crate) type Addresses =
Vec<(PhoenixSecretKey, PhoenixViewKey, PhoenixPublicKey)>;

const TRANSFER_CONTRACT: &str =
"0100000000000000000000000000000000000000000000000000000000000000";

Expand All @@ -34,11 +36,27 @@ const STAKE_CONTRACT: &str =
// Sync every 3 seconds for now
const SYNC_INTERVAL_SECONDS: u64 = 3;

pub struct Prover;

impl Prove for Prover {
fn prove(tx_circuit_vec_bytes: &[u8]) -> Result<Vec<u8>, WalletCoreError> {
let prover = RuskHttpClient::new("prover".to_string());
let prove_req =
RuskRequest::new("prove_execute", tx_circuit_vec_bytes.to_owned());

prover
.call(2, "rusk", &prove_req)
.wait()
.map_err(|e| WalletCoreError::PhoenixCircuit(e.to_string()))
}
}

/// The state struct is responsible for managing the state of the wallet
pub struct State {
cache: Mutex<Arc<Cache>>,
status: fn(&str),
client: RuskHttpClient,
addresses: Addresses,
prover: RuskHttpClient,
pub sync_rx: Option<Receiver<String>>,
}
Expand All @@ -50,14 +68,21 @@ impl State {
status: fn(&str),
client: RuskHttpClient,
prover: RuskHttpClient,
addresses: Vec<String>,
addresses: Vec<(PhoenixSecretKey, PhoenixViewKey, PhoenixPublicKey)>,
) -> Result<Self, Error> {
let cache =
Mutex::new(Arc::new(Cache::new(data_dir, &addresses, status)?));
let cfs = addresses
.iter()
.flat_map(|(_, _, pk)| {
[format!("{:?}", pk), format!("spent_{:?}", pk)]
})
.collect();

let cache = Mutex::new(Arc::new(Cache::new(data_dir, cfs, status)?));

Ok(Self {
cache,
sync_rx: None,
addresses,
status,
prover,
client,
Expand All @@ -66,17 +91,19 @@ impl State {

pub(crate) fn cache(&self) -> Arc<Cache> {
let state = self.cache.lock().unwrap();
Arc::clone(&state.cache)

Arc::clone(&state)
}

pub async fn register_sync(&self) -> Result<(), Error> {
pub async fn register_sync(&mut self) -> Result<(), Error> {
let (sync_tx, sync_rx) = flume::unbounded::<String>();

self.sync_rx = Some(sync_rx);

let cache = self.cache();
let status = self.status;
let client = self.client;
let client = &self.client;
let addresses = &self.addresses;
let sender = Arc::new(sync_tx);

status("Starting Sync..");
Expand All @@ -86,7 +113,8 @@ impl State {
let sender = Arc::clone(&sender);
let _ = sender.send("Syncing..".to_string());

let sync_status = sync_db(&client, &store, status).await;
let sync_status =
sync_db(client, &cache, &addresses.clone(), status).await;
let _ = match sync_status {
Ok(_) => sender.send("Syncing Complete".to_string()),
Err(e) => sender.send(format!("Error during sync:.. {e}")),
Expand All @@ -100,83 +128,97 @@ impl State {
}

pub async fn sync(&self) -> Result<(), Error> {
sync_db(&self.client, &self.store, &self.status).await
sync_db(&self.client, &self.cache(), &self.addresses, self.status).await
}

/// Requests that a node prove the given transaction and later propagates it
pub fn compute_proof_and_propagate(
&self,
utx: PhoenixTransaction,
) -> Result<Transaction, Error> {
self.status("Proving tx, please wait...");
let utx_bytes = utx.proof();
let prove_req = RuskRequest::new("prove_execute", utx_bytes);
let proof_bytes: Vec<u8> =
self.prover.call(2, "rusk", &prove_req).wait()?;
self.status("Proof success!");
utx.set_proof(proof_bytes);
let tx_bytes = utx.to_var_bytes();

self.status("Attempt to preverify tx...");
let preverify_req = RuskRequest::new("preverify", tx_bytes.clone());
let _ = self.client.call(2, "rusk", &preverify_req).wait()?;
self.status("Preverify success!");

self.status("Propagating tx...");
let propagate_req = RuskRequest::new("propagate_tx", tx_bytes);
let _ = self.client.call(2, "Chain", &propagate_req).wait()?;
self.status("Transaction propagated!");

Ok(tx)
pub fn propagate(&self, utx: Transaction) -> Result<Transaction, Error> {
if let Transaction::Phoenix(p) = utx {
let status = self.status;
let tx_bytes = utx.to_var_bytes();

status("Attempt to preverify tx...");
let preverify_req = RuskRequest::new("preverify", tx_bytes.clone());
let _ = self.client.call(2, "rusk", &preverify_req).wait()?;
status("Preverify success!");

status("Propagating tx...");
let propagate_req = RuskRequest::new("propagate_tx", tx_bytes);
let _ = self.client.call(2, "Chain", &propagate_req).wait()?;
status("Transaction propagated!");

Ok(Transaction::Phoenix(p))
} else {
Err(Error::Transaction(
"Only Phoenix transactions are supported".to_string(),
))
}
}

/// Find notes for a view key, starting from the given block height.
fn fetch_notes(
pub(crate) fn inputs(
&self,
index: u8,
target: u64,
) -> Result<Vec<(Note, Opening)>, Error> {
if let Some((_, vk, pk)) = self.addresses.get(index as usize) {
let inputs: Result<Inputs, Error> = self
.cache()
.notes(&pk)?
.into_iter()
.map(|data| Ok((data.note, data.note.value(Some(vk)).unwrap())))
.collect();

try_input_notes(inputs?, target)?
.into_iter()
.map(|(note, _)| {
let opening = self.fetch_opening(&note)?;

Ok((note, opening))
})
.collect()
} else {
Err(Error::AddressNotOwned)
}
}

pub(crate) fn fetch_notes(
&self,
pk: &PhoenixPublicKey,
) -> Result<Vec<EnrichedNote>, Error> {
Ok(state
.cache
.notes(&pk)?
) -> Result<Vec<NoteData>, Error> {
self.cache()
.notes(pk)?
.into_iter()
.map(|data| (data.note, data.height))
.collect())
.map(|data| {
Ok(NoteData {
note: data.note,
height: data.height,
})
})
.collect()
}

/// Fetch the current anchor of the state.
fn fetch_anchor(&self) -> Result<BlsScalar, Error> {
self.status("Fetching anchor...");
pub(crate) fn fetch_anchor(&self) -> Result<BlsScalar, Error> {
let status = self.status;
status("Fetching anchor...");

let anchor = self
.client
.contract_query::<(), 0>(TRANSFER_CONTRACT, "root", &())
.wait()?;
self.status("Anchor received!");
status("Anchor received!");
let anchor = rkyv::from_bytes(&anchor).map_err(|_| Error::Rkyv)?;
Ok(anchor)
}

/// Queries the node to find the opening for a specific note.
fn fetch_opening(&self, note: &Note) -> Result<Opening, Self::Error> {
self.status("Fetching opening notes...");

let data = self
.client
.contract_query::<_, 1024>(TRANSFER_CONTRACT, "opening", note.pos())
.wait()?;

self.status("Opening notes received!");

let branch = rkyv::from_bytes(&data).map_err(|_| Error::Rkyv)?;
Ok(branch)
}

/// Queries the node for the amount staked by a key.
fn fetch_stake(
pub(crate) fn fetch_stake(
&self,
pk: &PhoenixPublicKey,
) -> Result<StakeInfo, Self::Error> {
self.status("Fetching stake...");
) -> Result<Option<StakeData>, Error> {
let status = self.status;
status("Fetching stake...");

let data = self
.client
Expand All @@ -185,30 +227,28 @@ impl State {

let res: Option<StakeData> =
rkyv::from_bytes(&data).map_err(|_| Error::Rkyv)?;
self.status("Stake received!");
status("Stake received!");

let staking_address = pk.to_bytes().to_vec();
let staking_address = bs58::encode(staking_address).into_string();
println!("Staking address: {}", staking_address);

// FIX_ME: proper solution should to return an Option<StakeInfo>
// changing the trait implementation. That would reflect the state of
// the stake contract. It would be up to the consumer to decide what to
// do with a None
let stake = res
.map(
|StakeData {
amount,
reward,
counter,
}| StakeInfo {
amount,
reward,
counter,
},
)
.unwrap_or_default();

Ok(stake)
Ok(res)
}

/// Queries the node to find the opening for a specific note.
fn fetch_opening(&self, note: &Note) -> Result<Opening, Error> {
let status = self.status;
status("Fetching opening notes...");

let data = self
.client
.contract_query::<_, 1024>(TRANSFER_CONTRACT, "opening", note.pos())
.wait()?;

status("Opening notes received!");

let branch = rkyv::from_bytes(&data).map_err(|_| Error::Rkyv)?;
Ok(branch)
}
}
Loading

0 comments on commit 643945a

Please sign in to comment.