Skip to content

Commit

Permalink
To public optimization (#356)
Browse files Browse the repository at this point in the history
* pruning fix

* it works

* more things

* everything ready

* everything ready

* final touches

* changelog

* clippy

* final error found

* no removing paths

* modified extend

* remove optimization

* asset list method

* type asset_list_response

* asset list method takes normal ref

* asset list doesnt return zero assets

* consolidation

* consolidation prerequest

* clippy

* consolidation test

* test docs

* comment addressed

* estimate posts

* docs and changelog

* docs

* docs

* estimate transferposts correction

* done

* docs and changelog

* estimate posts update

* estimate again

* test

* comments addressed

* final touch

* comments addressed
  • Loading branch information
SupremoUGH authored Jun 19, 2023
1 parent 5753683 commit 70b3d08
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [\#353](https://github.com/Manta-Network/manta-rs/pull/353) Restore Merkle tree pruning for the wallet.

### Changed
- [\#356](https://github.com/Manta-Network/manta-rs/pull/356) Signer ToPublic optimization.

### Deprecated

Expand Down
235 changes: 201 additions & 34 deletions manta-accounting/src/wallet/signer/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
batch::Join,
canonical::{
MultiProvingContext, PrivateTransfer, PrivateTransferShape, Selection, ToPrivate,
ToPublic, Transaction, TransactionData, TransferShape,
ToPublic, ToPublicShape, Transaction, TransactionData, TransferShape,
},
receiver::ReceiverPost,
requires_authorization,
Expand All @@ -45,6 +45,7 @@ use crate::{
},
};
use alloc::{vec, vec::Vec};
use core::ops::SubAssign;
use manta_crypto::{
accumulator::{
Accumulator, BatchInsertion, FromItemsAndWitnesses, ItemHashFunction, OptimizedAccumulator,
Expand Down Expand Up @@ -807,6 +808,137 @@ where
Ok(into_array_unchecked(final_presenders))
}

/// Performs a ToPublic transaction spending the assets in `selection`,
/// returning [`TransferPost`]s.
#[allow(clippy::too_many_arguments)]
#[inline]
fn compute_to_public_transaction<C>(
accounts: &AccountTable<C>,
assets: &C::AssetMap,
parameters: &Parameters<C>,
proving_context: &MultiProvingContext<C>,
asset_id: &C::AssetId,
sink_accounts: Vec<C::AccountId>,
selection: Selection<C>,
utxo_accumulator: &mut C::UtxoAccumulator,
rng: &mut C::Rng,
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
{
let Selection {
mut change,
mut pre_senders,
} = selection;
let mut posts = Vec::new();
let mut iter = pre_senders
.into_iter()
.chunk_by::<{ ToPublicShape::SENDERS }>();
for chunk in &mut iter {
let senders = array_map(chunk, |s| {
s.try_upgrade(parameters, utxo_accumulator)
.expect("Unable to upgrade expected UTXO.")
});
process_to_public_senders(
accounts,
parameters,
proving_context,
asset_id,
senders,
sink_accounts.clone(),
utxo_accumulator,
&mut change,
&mut posts,
rng,
)?;
}
pre_senders = iter.remainder();
if !pre_senders.is_empty() {
let final_senders = into_array_unchecked(prepare_final_pre_senders(
accounts,
assets,
utxo_accumulator,
parameters,
asset_id,
Default::default(),
pre_senders,
rng,
)?);
process_to_public_senders(
accounts,
parameters,
proving_context,
asset_id,
final_senders,
sink_accounts,
utxo_accumulator,
&mut change,
&mut posts,
rng,
)?;
}
Ok(SignResponse::new(posts))
}

/// Creates a to public [`TransferPost`] spending the assets held by `senders` and
/// attaches it to `post`.
#[allow(clippy::too_many_arguments)]
#[inline]
fn process_to_public_senders<C>(
accounts: &AccountTable<C>,
parameters: &Parameters<C>,
proving_context: &MultiProvingContext<C>,
asset_id: &C::AssetId,
senders: [Sender<C>; ToPublicShape::SENDERS],
sink_accounts: Vec<C::AccountId>,
utxo_accumulator: &mut C::UtxoAccumulator,
change: &mut C::AssetValue,
posts: &mut Vec<TransferPost<C>>,
rng: &mut C::Rng,
) -> Result<(), SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
{
let authorization = authorization_for_default_spending_key::<C>(accounts, parameters, rng);
let mut received_value = C::AssetValue::default();
let mut reclaimed_value = senders
.iter()
.map(|sender| sender.asset().value)
.sum::<C::AssetValue>();
if reclaimed_value >= *change {
received_value += change.clone();
reclaimed_value -= received_value.clone();
*change = Default::default();
} else {
received_value += reclaimed_value.clone();
*change -= reclaimed_value;
reclaimed_value = Default::default();
}
let receiver = default_receiver::<C>(
accounts,
parameters,
Asset::<C>::new(asset_id.clone(), received_value),
rng,
);
posts.push(build_post(
Some(accounts),
utxo_accumulator.model(),
parameters,
&proving_context.to_public,
ToPublic::build(
authorization,
senders,
[receiver],
Asset::<C>::new(asset_id.clone(), reclaimed_value),
),
sink_accounts,
rng,
)?);
Ok(())
}

/// Returns the [`Address`] corresponding to `authorization_context`.
#[inline]
pub fn address<C>(
Expand Down Expand Up @@ -935,6 +1067,7 @@ fn sign_withdraw<C>(
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
{
let selection = select(accounts, assets, &parameters.parameters, &asset, rng)?;
sign_after_selection(
Expand Down Expand Up @@ -962,6 +1095,7 @@ fn consolidate_internal<C>(
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
C::Identifier: PartialEq,
{
let asset = request.asset();
Expand All @@ -979,18 +1113,16 @@ where
)
}

/// Signs a withdraw transaction for `asset` sent to `address`, where `selection`
/// owns at least `asset`.
/// Signs a private transfer of `asset` to `address`.
#[allow(clippy::too_many_arguments)]
#[inline]
fn sign_after_selection<C>(
fn sign_after_selection_private_transfer<C>(
parameters: &SignerParameters<C>,
accounts: &AccountTable<C>,
assets: &C::AssetMap,
utxo_accumulator: &mut C::UtxoAccumulator,
asset: Asset<C>,
address: Option<Address<C>>,
sink_accounts: Vec<C::AccountId>,
address: Address<C>,
selection: Selection<C>,
rng: &mut C::Rng,
) -> Result<SignResponse<C>, SignError<C>>
Expand All @@ -1017,37 +1149,68 @@ where
);
let authorization =
authorization_for_default_spending_key::<C>(accounts, &parameters.parameters, rng);
let final_post = match address {
Some(address) => {
let receiver = receiver::<C>(
&parameters.parameters,
address,
asset,
Default::default(),
rng,
);
build_post(
Some(accounts),
utxo_accumulator.model(),
&parameters.parameters,
&parameters.proving_context.private_transfer,
PrivateTransfer::build(authorization, senders, [change, receiver]),
Vec::new(),
rng,
)?
}
_ => build_post(
Some(accounts),
utxo_accumulator.model(),
let receiver = receiver::<C>(
&parameters.parameters,
address,
asset,
Default::default(),
rng,
);
let final_post = build_post(
Some(accounts),
utxo_accumulator.model(),
&parameters.parameters,
&parameters.proving_context.private_transfer,
PrivateTransfer::build(authorization, senders, [change, receiver]),
Vec::new(),
rng,
)?;
posts.push(final_post);
Ok(SignResponse::new(posts))
}

/// Signs a withdraw transaction for `asset` sent to `address`, where `selection`
/// owns at least `asset`.
#[allow(clippy::too_many_arguments)]
#[inline]
fn sign_after_selection<C>(
parameters: &SignerParameters<C>,
accounts: &AccountTable<C>,
assets: &C::AssetMap,
utxo_accumulator: &mut C::UtxoAccumulator,
asset: Asset<C>,
address: Option<Address<C>>,
sink_accounts: Vec<C::AccountId>,
selection: Selection<C>,
rng: &mut C::Rng,
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
{
match address {
Some(address) => sign_after_selection_private_transfer(
parameters,
accounts,
assets,
utxo_accumulator,
asset,
address,
selection,
rng,
),
_ => compute_to_public_transaction(
accounts,
assets,
&parameters.parameters,
&parameters.proving_context.to_public,
ToPublic::build(authorization, senders, [change], asset),
&parameters.proving_context,
&asset.id,
sink_accounts,
selection,
utxo_accumulator,
rng,
)?,
};
posts.push(final_post);
Ok(SignResponse::new(posts))
),
}
}

/// Signs the `transaction`, generating transfer posts without releasing resources.
Expand All @@ -1063,6 +1226,7 @@ fn sign_internal<C>(
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
{
match transaction {
Transaction::ToPrivate(asset) => {
Expand Down Expand Up @@ -1118,6 +1282,7 @@ pub fn sign<C>(
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
{
let result = sign_internal(
parameters,
Expand Down Expand Up @@ -1145,6 +1310,7 @@ pub fn consolidate<C>(
) -> Result<SignResponse<C>, SignError<C>>
where
C: Configuration,
C::AssetValue: SubAssign,
C::Identifier: PartialEq,
{
let result = consolidate_internal(
Expand Down Expand Up @@ -1270,6 +1436,7 @@ pub fn sign_with_transaction_data<C>(
) -> SignWithTransactionDataResult<C>
where
C: Configuration,
C::AssetValue: SubAssign,
TransferPost<C>: Clone,
{
Ok(SignWithTransactionDataResponse(
Expand Down
16 changes: 11 additions & 5 deletions manta-accounting/src/wallet/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use crate::{
wallet::ledger::{self, Data},
};
use alloc::{boxed::Box, vec::Vec};
use core::{cmp::max, convert::Infallible, fmt::Debug, hash::Hash};
use core::{cmp::max, convert::Infallible, fmt::Debug, hash::Hash, ops::SubAssign};
use manta_crypto::{
accumulator::{
Accumulator, BatchInsertion, ExactSizeAccumulator, FromItemsAndWitnesses, ItemHashFunction,
Expand Down Expand Up @@ -1640,7 +1640,10 @@ where

/// Signs the `transaction`, generating transfer posts.
#[inline]
pub fn sign(&mut self, transaction: Transaction<C>) -> Result<SignResponse<C>, SignError<C>> {
pub fn sign(&mut self, transaction: Transaction<C>) -> Result<SignResponse<C>, SignError<C>>
where
C::AssetValue: SubAssign,
{
functions::sign(
&self.parameters,
self.state.accounts.as_ref(),
Expand All @@ -1664,6 +1667,7 @@ where
request: ConsolidationPrerequest<C>,
) -> Result<SignResponse<C>, SignError<C>>
where
C::AssetValue: SubAssign,
C::Identifier: PartialEq,
{
functions::consolidate(
Expand Down Expand Up @@ -1741,6 +1745,7 @@ where
transaction: Transaction<C>,
) -> Result<SignWithTransactionDataResponse<C>, SignError<C>>
where
C::AssetValue: SubAssign,
TransferPost<C>: Clone,
{
functions::sign_with_transaction_data(
Expand Down Expand Up @@ -1835,16 +1840,17 @@ where
max(self.state.assets.select(asset).values.len() - 1, 1)
}
Transaction::ToPublic(asset, _) => {
max(self.state.assets.select(asset).values.len() - 1, 1)
} // note: change the estimation once we implement the topublic optimization
(self.state.assets.select(asset).values.len() + 1) / 2
}
}
}
}

impl<C> Connection<C> for Signer<C>
where
C: Configuration,
C::AssetValue: CheckedAdd<Output = C::AssetValue> + CheckedSub<Output = C::AssetValue>,
C::AssetValue:
CheckedAdd<Output = C::AssetValue> + CheckedSub<Output = C::AssetValue> + SubAssign,
C::Identifier: PartialEq,
{
type AssetMetadata = C::AssetMetadata;
Expand Down
Loading

0 comments on commit 70b3d08

Please sign in to comment.