Skip to content

Commit

Permalink
wip - utxo selection refactoring
Browse files Browse the repository at this point in the history
using refs for Secret
refactor misc deserializations in favor of TryFrom
  • Loading branch information
aspect committed Jun 29, 2023
1 parent 1e5ceaa commit cf71692
Show file tree
Hide file tree
Showing 31 changed files with 702 additions and 509 deletions.
9 changes: 9 additions & 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ md-5 = "0.10.5"
derivative = "2.2.0"
num = "0.4.0"
textwrap = "0.16"
sorted-insert = "0.2.3"


# bip32 dependencies
rand_core = { version = "0.6", features = ["std"] }
Expand Down
1 change: 0 additions & 1 deletion consensus/core/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ impl TryFrom<JsValue> for Header {
type Error = Error;
fn try_from(js_value: JsValue) -> std::result::Result<Self, Self::Error> {
if let Some(object) = Object::try_from(&js_value) {

let parents_by_level = object
.get_vec("parentsByLevel")?
.iter()
Expand Down
2 changes: 1 addition & 1 deletion consensus/core/src/networktype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display, Formatter};
use std::ops::Deref;
use std::str::FromStr;
use workflow_core::enums::u8_try_from;
use wasm_bindgen::prelude::*;
use workflow_core::enums::u8_try_from;

#[derive(thiserror::Error, PartialEq, Eq, Debug, Clone)]
pub enum NetworkTypeError {
Expand Down
2 changes: 2 additions & 0 deletions crypto/addresses/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ license.workspace = true

[dependencies]
borsh.workspace = true
js-sys.workspace = true
serde.workspace = true
smallvec.workspace = true
thiserror.workspace = true
wasm-bindgen.workspace = true
workflow-wasm.workspace = true

[dev-dependencies]
criterion.workspace = true
Expand Down
97 changes: 34 additions & 63 deletions crypto/addresses/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use smallvec::SmallVec;
use std::collections::HashMap;
// use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use thiserror::Error;
use wasm_bindgen::convert::FromWasmAbi;
// use wasm_bindgen::convert::FromWasmAbi;
use js_sys::Object;
use wasm_bindgen::prelude::*;
use workflow_wasm::object::*;

mod bech32;

#[derive(Error, PartialEq, Eq, Debug, Clone)]
// #[derive(Error, Debug)]
pub enum AddressError {
#[error("Invalid prefix {0}")]
InvalidPrefix(String),
Expand All @@ -20,11 +23,26 @@ pub enum AddressError {
#[error("Invalid version {0}")]
InvalidVersion(u8),

#[error("Invalid version {0}")]
InvalidVersionString(String),

#[error("Invalid character {0}")]
DecodingError(char),

#[error("Checksum is invalid")]
BadChecksum,

#[error("Invalid address")]
InvalidAddress,

#[error("{0}")]
WASM(String),
}

impl From<workflow_wasm::error::Error> for AddressError {
fn from(e: workflow_wasm::error::Error) -> Self {
AddressError::WASM(e.to_string())
}
}

#[derive(
Expand Down Expand Up @@ -293,10 +311,7 @@ impl TryFrom<String> for Address {
type Error = AddressError;

fn try_from(value: String) -> Result<Self, Self::Error> {
match value.split_once(':') {
Some((prefix, payload)) => Self::decode_payload(prefix.try_into()?, payload),
None => Err(AddressError::MissingPrefix),
}
value.as_str().try_into()
}
}

Expand Down Expand Up @@ -325,67 +340,23 @@ impl<'de> Deserialize<'de> for Address {
where
D: Deserializer<'de>,
{
// let s = <std::string::String as Deserialize>::deserialize(deserializer)?;
// Ok(s.try_into().map_err(serde::de::Error::custom)?)
let address = deserializer.deserialize_any(AddressVisitor)?;
Ok(address)
let s = <std::string::String as Deserialize>::deserialize(deserializer)?;
s.try_into().map_err(serde::de::Error::custom)
}
}

struct AddressVisitor;

impl<'de> serde::de::Visitor<'de> for AddressVisitor {
type Value = Address;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "valid address as string or Address object.")
}

fn visit_str<E>(self, str: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Address::try_from(str).map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &self))
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let key = map.next_key::<String>()?.ok_or(serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))?;

if key.eq("ptr") {
let value = map.next_value::<u32>()?;
return Ok(unsafe { Address::from_abi(value) });
}

if key.eq("version") || key.eq("prefix") || key.eq("payload") {
let mut set = HashMap::new();
let value = map.next_value::<String>().map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))?;
set.insert(key, value);

let key = map.next_key::<String>()?.ok_or(serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))?;
let value = map.next_value::<String>().map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))?;
set.insert(key, value);

let key = map.next_key::<String>()?.ok_or(serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))?;
let value = map.next_value::<String>().map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))?;
set.insert(key, value);

if !set.contains_key("version") || !set.contains_key("prefix") || !set.contains_key("payload") {
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self));
}

let prefix = set.get("prefix").unwrap();
let payload = set.get("payload").unwrap();

let address_str = format!("{prefix}:{payload}");

return Address::try_from(address_str).map_err(|e| serde::de::Error::custom(e.to_string()));
impl TryFrom<JsValue> for Address {
type Error = AddressError;
fn try_from(js_value: JsValue) -> Result<Self, Self::Error> {
if let Some(string) = js_value.as_string() {
Address::try_from(string)
} else if let Some(object) = Object::try_from(&js_value) {
let prefix: Prefix = object.get_string("prefix")?.as_str().try_into()?;
let payload = object.get_string("payload")?; //.as_str();
Self::decode_payload(prefix, &payload)
} else {
Err(AddressError::InvalidAddress)
}

Err(serde::de::Error::invalid_value(serde::de::Unexpected::Map, &self))
//Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(&format!("Invalid address: {{{key:?}:{value:?}}}")), &self))
}
}

Expand Down
22 changes: 22 additions & 0 deletions utils/src/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,25 @@ where
}
}
}

pub trait GroupExtension<K, V, I>
where
K: std::hash::Hash + Ord,
I: IntoIterator<Item = (K, V)>,
{
fn group_from(v: I) -> HashMap<K, Vec<V>>;
}

impl<K, V, I> GroupExtension<K, V, I> for HashMap<K, Vec<V>>
where
K: std::hash::Hash + Ord,
I: IntoIterator<Item = (K, V)>,
{
fn group_from(v: I) -> HashMap<K, Vec<V>> {
let mut result = HashMap::<K, Vec<V>>::new();
for (a, b) in v {
result.entry(a).or_default().push(b);
}
result
}
}
19 changes: 12 additions & 7 deletions wallet/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use kaspa_wallet_core::accounts::gen0::import::*;
use kaspa_wallet_core::imports::ToHex;
use kaspa_wallet_core::runtime::wallet::WalletCreateArgs;
use kaspa_wallet_core::storage::{AccountKind, IdT, PrvKeyDataId, PrvKeyDataInfo};
use kaspa_wallet_core::tx::PaymentOutputs;
use kaspa_wallet_core::{runtime::wallet::AccountCreateArgs, runtime::Wallet, secret::Secret};
use kaspa_wallet_core::{Address, AddressPrefix, ConnectOptions, ConnectStrategy};
// use serde::de::DeserializeOwned;
Expand Down Expand Up @@ -147,10 +148,10 @@ impl WalletCli {
if !is_open {
return Err(Error::WalletIsNotOpen);
}
//- TODO
//- TODO
//- TODO
//- TODO
//- TODO
//- TODO
//- TODO
//- TODO
// let account_kind: AccountKind = select_variant(&term, "Please select account type", &mut argv).await?;

// let prv_key_data_info =
Expand Down Expand Up @@ -211,7 +212,8 @@ impl WalletCli {
let amount = argv.get(1).unwrap();
let priority_fee = argv.get(2);

let priority_fee_sompi = if let Some(fee) = priority_fee { helpers::kas_str_to_sompi(fee)? } else { 0u64 };
let priority_fee_sompi = if let Some(fee) = priority_fee { Some(helpers::kas_str_to_sompi(fee)?) } else { None };

let address = serde_json::from_str::<Address>(address)?;
let amount_sompi = helpers::kas_str_to_sompi(amount)?;

Expand All @@ -226,9 +228,11 @@ impl WalletCli {
return Err("It is read only wallet.".into());
}
let abortable = Abortable::default();

let outputs = PaymentOutputs::try_from((address.clone(), amount_sompi))?;
let ids =
// account.send(&address, amount_sompi, priority_fee_sompi, keydata.unwrap(), payment_secret, &abortable).await?;
account.send(&address, amount_sompi, priority_fee_sompi, wallet_secret, payment_secret, &abortable).await?;
account.send(&outputs, priority_fee_sompi, false, wallet_secret, payment_secret, &abortable).await?;

term.writeln(format!("\r\nSending {amount} KAS to {address}, tx ids:"));
term.writeln(format!("{}\r\n", ids.into_iter().map(|a| a.to_string()).collect::<Vec<_>>().join("\r\n")));
Expand Down Expand Up @@ -446,7 +450,8 @@ impl WalletCli {

let payment_secret = term.ask(true, "Enter payment (private key encryption) password (optional): ").await?;
// let payment_secret = payment_secret.trim();
let payment_secret = if payment_secret.trim().is_empty() { None } else { Some(Secret::new(payment_secret.trim().as_bytes().to_vec())) };
let payment_secret =
if payment_secret.trim().is_empty() { None } else { Some(Secret::new(payment_secret.trim().as_bytes().to_vec())) };

// let payment_secret = Secret::new(
// .as_bytes().to_vec(),
Expand Down
2 changes: 2 additions & 0 deletions wallet/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ aes.workspace = true
pbkdf2.workspace = true
derivative.workspace = true
downcast.workspace = true
sorted-insert.workspace = true


[dependencies.web-sys]
workspace = true
Expand Down
Loading

0 comments on commit cf71692

Please sign in to comment.