Skip to content

Commit

Permalink
Generalize Wallets and Fix Receiving Key Encoding (#33)
Browse files Browse the repository at this point in the history
* feat: generalize simulation to all wallets

* fix: use correct feature requirements for simulation

* fix: use correct receiving key encoding
  • Loading branch information
bhgomes authored and tsunrise committed Mar 18, 2022
1 parent be06041 commit fdc09da
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 149 deletions.
123 changes: 110 additions & 13 deletions manta-accounting/src/wallet/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@

use crate::{
asset::{Asset, AssetList},
transfer::{canonical::Transaction, Configuration, PublicKey, ReceivingKey},
transfer::{self, canonical::Transaction, PublicKey, ReceivingKey},
wallet::{
self, ledger,
ledger,
signer::{self, ReceivingKeyRequest},
Wallet,
BalanceState, Error, Wallet,
},
};
use alloc::sync::Arc;
Expand All @@ -43,7 +43,7 @@ pub mod sim;
/// Simulation Action Space
pub enum Action<C>
where
C: Configuration,
C: transfer::Configuration,
{
/// No Action
Skip,
Expand Down Expand Up @@ -187,7 +187,7 @@ pub trait PublicBalanceOracle {
/// Actor
pub struct Actor<C, L, S>
where
C: Configuration,
C: transfer::Configuration,
L: ledger::Connection<C>,
S: signer::Connection<C>,
{
Expand All @@ -203,7 +203,7 @@ where

impl<C, L, S> Actor<C, L, S>
where
C: Configuration,
C: transfer::Configuration,
L: ledger::Connection<C>,
S: signer::Connection<C>,
{
Expand Down Expand Up @@ -265,18 +265,18 @@ where

/// Simulation Event
#[derive(derivative::Derivative)]
#[derivative(Debug(bound = "wallet::Error<C, L, S>: Debug"))]
#[derivative(Debug(bound = "Error<C, L, S>: Debug"))]
pub struct Event<C, L, S>
where
C: Configuration,
C: transfer::Configuration,
L: ledger::Connection<C>,
S: signer::Connection<C>,
{
/// Action Type
pub action: ActionType,

/// Action Result
pub result: Result<bool, wallet::Error<C, L, S>>,
pub result: Result<bool, Error<C, L, S>>,
}

/// Public Key Database
Expand All @@ -290,7 +290,7 @@ pub type SharedPublicKeyDatabase<C> = Arc<RwLock<PublicKeyDatabase<C>>>;
#[derivative(Default(bound = ""))]
pub struct Simulation<C, L, S>
where
C: Configuration,
C: transfer::Configuration,
L: ledger::Connection<C>,
S: signer::Connection<C>,
PublicKey<C>: Eq + Hash,
Expand All @@ -304,7 +304,7 @@ where

impl<C, L, S> Simulation<C, L, S>
where
C: Configuration,
C: transfer::Configuration,
L: ledger::Connection<C>,
S: signer::Connection<C>,
PublicKey<C>: Eq + Hash,
Expand All @@ -321,7 +321,7 @@ where

impl<C, L, S> sim::ActionSimulation for Simulation<C, L, S>
where
C: Configuration,
C: transfer::Configuration,
L: ledger::Connection<C> + PublicBalanceOracle,
S: signer::Connection<C>,
PublicKey<C>: Eq + Hash,
Expand Down Expand Up @@ -412,9 +412,106 @@ where
}
Ok(true)
}
Err(err) => Err(wallet::Error::SignerConnectionError(err)),
Err(err) => Err(Error::SignerConnectionError(err)),
},
},
}
}
}

/// Measures the public and secret balances for each wallet, summing them all together.
#[inline]
pub fn measure_balances<'w, C, L, S, I>(wallets: I) -> Result<AssetList, Error<C, L, S>>
where
C: 'w + transfer::Configuration,
L: 'w + ledger::Connection<C> + PublicBalanceOracle,
S: 'w + signer::Connection<C>,
I: IntoIterator<Item = &'w mut Wallet<C, L, S>>,
{
let mut balances = AssetList::new();
for wallet in wallets {
wallet.sync()?;
balances.deposit_all(wallet.ledger().public_balances().unwrap());
balances.deposit_all(
wallet
.assets()
.iter()
.map(|(id, value)| Asset::new(*id, *value)),
);
}
Ok(balances)
}

/// Simulation Configuration
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct Config {
/// Actor Count
pub actor_count: usize,

/// Actor Lifetime
pub actor_lifetime: usize,
}

impl Config {
/// Runs the simulation on the configuration defined in `self`.
#[cfg(feature = "parallel")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "parallel")))]
#[inline]
pub fn run<C, L, S, R, GL, GS, F>(
&self,
mut ledger: GL,
mut signer: GS,
rng: F,
) -> Result<bool, Error<C, L, S>>
where
C: transfer::Configuration + Send,
L: ledger::Connection<C> + PublicBalanceOracle + Send + Sync,
S: signer::Connection<C> + Send + Sync,
R: CryptoRng + RngCore + Send,
GL: FnMut(usize) -> L,
GS: FnMut(usize) -> S,
F: FnMut() -> R,
L::Checkpoint: Send,
Error<C, L, S>: Debug + Send,
PublicKey<C>: Eq + Hash + Send + Sync,
{
println!("[INFO] Building {:?} Wallets", self.actor_count);

let actors = (0..self.actor_count)
.map(|i| {
Actor::new(
Wallet::new(ledger(i), signer(i)),
Default::default(),
self.actor_lifetime,
)
})
.collect::<Vec<_>>();

let mut simulator = sim::Simulator::new(sim::ActionSim(Simulation::default()), actors);

let initial_balances =
measure_balances(simulator.actors.iter_mut().map(|actor| &mut actor.wallet))?;

println!("[INFO] Starting Simulation\n");

rayon::in_place_scope(|scope| {
for event in simulator.run(rng, scope) {
match event.event.action {
ActionType::Skip | ActionType::GeneratePublicKey => {}
_ => println!("{:?}", event),
}
if let Err(err) = event.event.result {
println!("\n[ERROR] Simulation Error: {:?}\n", err);
break;
}
}
});

println!("\n[INFO] Simulation Ended");

let final_balances =
measure_balances(simulator.actors.iter_mut().map(|actor| &mut actor.wallet))?;

Ok(initial_balances == final_balances)
}
}
4 changes: 2 additions & 2 deletions manta-pay/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ http = ["futures", "reqwest", "serde"]
scale = ["scale-codec", "scale-info"]

# Serde
serde = ["bs58", "manta-accounting/serde", "manta-crypto/serde", "serde_json"]
serde = ["manta-accounting/serde", "manta-crypto/serde"]

# Simulation Framework
simulation = [
Expand All @@ -84,7 +84,7 @@ test = ["manta-accounting/test", "manta-crypto/test"]
wallet = ["bip32", "manta-crypto/getrandom", "std"]

# Enable WebSocket Signer Client
websocket = ["serde", "std", "tungstenite"]
websocket = ["serde", "serde_json", "std", "tungstenite"]

[dependencies]
aes-gcm = { version = "0.9.4", default-features = false, features = ["aes", "alloc"] }
Expand Down
32 changes: 31 additions & 1 deletion manta-pay/src/bin/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,38 @@
// TODO: Add CLI interface and configuration for simulation parameters. See the old simulation code
// `test/simulation/mod.rs` for more information.

use manta_accounting::transfer::canonical::generate_context;
use manta_crypto::rand::{OsRng, Rand};
use manta_pay::{
config::FullParameters,
simulation::{ledger::Ledger, Simulation},
};

/// Runs the Manta Pay simulation.
#[inline]
pub fn main() {
manta_pay::simulation::simulate(10, 10);
let mut rng = OsRng;
let parameters = rng.gen();
let utxo_accumulator_model = rng.gen();

let (proving_context, verifying_context) = generate_context(
&(),
FullParameters::new(&parameters, &utxo_accumulator_model),
&mut rng,
)
.expect("Failed to generate contexts.");

Simulation {
actor_count: 10,
actor_lifetime: 10,
asset_id_count: 3,
starting_balance: 1000000,
}
.run(
&parameters,
&utxo_accumulator_model,
&proving_context,
Ledger::new(utxo_accumulator_model.clone(), verifying_context),
&mut rng,
)
}
36 changes: 21 additions & 15 deletions manta-pay/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use manta_crypto::{
};
use manta_util::codec::{Decode, DecodeError, Encode, Read, Write};

#[cfg(feature = "serde")]
#[cfg(feature = "bs58")]
use alloc::string::String;

#[cfg(any(feature = "test", test))]
Expand Down Expand Up @@ -706,25 +706,31 @@ pub type SpendingKey = transfer::SpendingKey<Config>;
pub type ReceivingKey = transfer::ReceivingKey<Config>;

/// Converts a [`ReceivingKey`] into a base58-encoded string.
#[cfg(feature = "serde")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
#[cfg(feature = "bs58")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "bs58")))]
#[inline]
pub fn receiving_key_to_base58(receiving_key: &ReceivingKey) -> String {
bs58::encode(
serde_json::to_string(receiving_key)
.expect("Can always serialize to JSON.")
.as_bytes(),
)
.into_string()
let mut bytes = Vec::new();
receiving_key
.spend
.encode(&mut bytes)
.expect("Encoding is not allowed to fail.");
receiving_key
.view
.encode(&mut bytes)
.expect("Encoding is not allowed to fail.");
bs58::encode(bytes).into_string()
}

/// Converts a base58-encoded string into a [`ReceivingKey`].
#[cfg(feature = "serde")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
#[cfg(feature = "bs58")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "bs58")))]
#[inline]
pub fn receiving_key_from_base58(string: &str) -> Option<ReceivingKey> {
serde_json::from_str(
core::str::from_utf8(&bs58::decode(string.as_bytes()).into_vec().ok()?).ok()?,
)
.ok()
let bytes = bs58::decode(string.as_bytes()).into_vec().ok()?;
let (spend, view) = bytes.split_at(bytes.len() / 2);
Some(ReceivingKey {
spend: spend.to_owned().try_into().ok()?,
view: view.to_owned().try_into().ok()?,
})
}
2 changes: 1 addition & 1 deletion manta-pay/src/crypto/ecc/arkworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ where

/// Converts `point` into its canonical byte-representation.
#[inline]
fn affine_point_as_bytes<C>(point: &C::Affine) -> Vec<u8>
pub fn affine_point_as_bytes<C>(point: &C::Affine) -> Vec<u8>
where
C: ProjectiveCurve,
{
Expand Down
3 changes: 3 additions & 0 deletions manta-pay/src/simulation/ledger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

//! Ledger Simulation

// TODO: How to model existential deposits and fee payments?
// TODO: Add in some concurrency (and measure how much we need it).

use crate::{
config::{
Config, EncryptedNote, MerkleTreeConfiguration, MultiVerifyingContext, ProofSystem,
Expand Down
Loading

0 comments on commit fdc09da

Please sign in to comment.