Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve ledger API flexibility and encoding #59

Merged
merged 3 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions manta-accounting/src/wallet/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@

//! Ledger Connection

// TODO: Report a more meaningful error on `push` failure. In some way, it must match the
// `TransferPostError` variants.

use crate::transfer::{Configuration, EncryptedNote, TransferPost, Utxo, VoidNumber};
use alloc::vec::Vec;
use core::{fmt::Debug, hash::Hash};
Expand All @@ -28,16 +25,20 @@ use manta_util::future::LocalBoxFutureResult;
use manta_util::serde::{Deserialize, Serialize};

/// Ledger Checkpoint
///
/// The checkpoint type is responsible for keeping the ledger, signer, and wallet in sync with each
/// other making sure that they all have the same view of the ledger state. Checkpoints should
/// be orderable with a bottom element returned by [`Default::default`].
pub trait Checkpoint: Default + PartialOrd {
/// Returns the index into the receiver set for the ledger.
///
/// This index is used to ensure that wallets are synchronized even during connection failures
/// or other errors during synchronization.
fn receiver_index(&self) -> usize;

/// Returns the index into the sender set for the ledger.
fn sender_index(&self) -> usize;
}

/// Ledger Source Connection
pub trait Connection<C>
/// Ledger Pull Configuration
pub trait PullConfiguration<C>
where
C: Configuration,
{
Expand All @@ -49,7 +50,13 @@ where

/// Sender Chunk Iterator Type
type SenderChunk: IntoIterator<Item = VoidNumber<C>>;
}

/// Ledger Source Connection
pub trait Connection<C>: PullConfiguration<C>
where
C: Configuration,
{
/// Push Response Type
///
/// This is the return type of the [`push`](Self::push) method. Use this type to customize the
Expand All @@ -60,10 +67,15 @@ where
type PushResponse;

/// Error Type
///
/// This error type corresponds to the communication channel itself setup by the [`Connection`]
/// rather than any errors introduced by the [`pull`](Self::pull) or [`push`](Self::push)
/// methods themselves which would correspond to an empty [`PullResponse`] or whatever error
/// variants are stored in [`PushResponse`](Self::PushResponse).
type Error;

/// Pulls receiver data from the ledger starting from `checkpoint`, returning the current
/// [`Checkpoint`](Self::Checkpoint).
/// [`Checkpoint`](PullConfiguration::Checkpoint).
fn pull<'s>(
&'s mut self,
checkpoint: &'s Self::Checkpoint,
Expand Down Expand Up @@ -116,7 +128,7 @@ where
pub struct PullResponse<C, L>
where
C: Configuration,
L: Connection<C> + ?Sized,
L: PullConfiguration<C> + ?Sized,
{
/// Pull Continuation Flag
///
Expand All @@ -127,7 +139,7 @@ where
/// Ledger Checkpoint
///
/// If the `should_continue` flag is set to `true` then `checkpoint` is the next
/// [`Checkpoint`](Connection::Checkpoint) to request data from the ledger. Otherwise, it
/// [`Checkpoint`](PullConfiguration::Checkpoint) to request data from the ledger. Otherwise, it
/// represents the current ledger state.
pub checkpoint: L::Checkpoint,

Expand Down
4 changes: 2 additions & 2 deletions manta-accounting/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ where
&self.ledger
}

/// Returns the [`Checkpoint`](ledger::Connection::Checkpoint) representing the current state
/// of this wallet.
/// Returns the [`Checkpoint`](ledger::PullConfiguration::Checkpoint) representing the current
/// state of this wallet.
#[inline]
pub fn checkpoint(&self) -> &L::Checkpoint {
&self.checkpoint
Expand Down
113 changes: 113 additions & 0 deletions manta-pay/src/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,122 @@ impl Default for Checkpoint {
}
}

impl From<RawCheckpoint> for Checkpoint {
#[inline]
fn from(checkpoint: RawCheckpoint) -> Self {
Self::new(
checkpoint.receiver_index.map(|i| i as usize).into(),
checkpoint.sender_index as usize,
)
}
}

impl ledger::Checkpoint for Checkpoint {
#[inline]
fn receiver_index(&self) -> usize {
self.receiver_index.iter().sum()
}

#[inline]
fn sender_index(&self) -> usize {
self.sender_index
}
}

#[cfg(feature = "scale")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "scale")))]
impl scale_codec::Decode for Checkpoint {
#[inline]
fn decode<I>(input: &mut I) -> Result<Self, scale_codec::Error>
where
I: scale_codec::Input,
{
RawCheckpoint::decode(input).map(Into::into)
}
}

#[cfg(feature = "scale")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "scale")))]
impl scale_codec::Encode for Checkpoint {
#[inline]
fn using_encoded<R, Encoder>(&self, f: Encoder) -> R
where
Encoder: FnOnce(&[u8]) -> R,
{
RawCheckpoint::from(*self).using_encoded(f)
}
}

#[cfg(feature = "scale")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "scale")))]
impl scale_codec::EncodeLike for Checkpoint {}

#[cfg(feature = "scale")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "scale")))]
impl scale_codec::MaxEncodedLen for Checkpoint {
#[inline]
fn max_encoded_len() -> usize {
RawCheckpoint::max_encoded_len()
}
}

#[cfg(feature = "scale")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "scale")))]
impl scale_info::TypeInfo for Checkpoint {
type Identity = RawCheckpoint;

#[inline]
fn type_info() -> scale_info::Type {
Self::Identity::type_info()
}
}

/// Raw Checkpoint for Encoding and Decoding
#[cfg_attr(
feature = "scale",
derive(
scale_codec::Decode,
scale_codec::Encode,
scale_codec::MaxEncodedLen,
scale_info::TypeInfo
)
)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct RawCheckpoint {
/// Receiver Index
pub receiver_index: [u64; MerkleTreeConfiguration::FOREST_WIDTH],

/// Sender Index
pub sender_index: u64,
}

impl RawCheckpoint {
/// Builds a new [`RawCheckpoint`] from `receiver_index` and `sender_index`.
#[inline]
pub fn new(
receiver_index: [u64; MerkleTreeConfiguration::FOREST_WIDTH],
sender_index: u64,
) -> Self {
Self {
receiver_index,
sender_index,
}
}
}

impl Default for RawCheckpoint {
#[inline]
fn default() -> Self {
Self::new([0; MerkleTreeConfiguration::FOREST_WIDTH], 0)
}
}

impl From<Checkpoint> for RawCheckpoint {
#[inline]
fn from(checkpoint: Checkpoint) -> Self {
Self::new(
(*checkpoint.receiver_index).map(|i| i as u64),
checkpoint.sender_index as u64,
)
}
}
5 changes: 4 additions & 1 deletion manta-pay/src/simulation/ledger/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ impl Client {
}
}

impl ledger::Connection<Config> for Client {
impl ledger::PullConfiguration<Config> for Client {
type Checkpoint = Checkpoint;
type ReceiverChunk = Vec<(Utxo, EncryptedNote)>;
type SenderChunk = Vec<VoidNumber>;
}

impl ledger::Connection<Config> for Client {
type PushResponse = bool;
type Error = Error;

Expand Down
5 changes: 4 additions & 1 deletion manta-pay/src/simulation/ledger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,10 +439,13 @@ impl LedgerConnection {
}
}

impl ledger::Connection<Config> for LedgerConnection {
impl ledger::PullConfiguration<Config> for LedgerConnection {
type Checkpoint = Checkpoint;
type ReceiverChunk = Vec<(Utxo, EncryptedNote)>;
type SenderChunk = Vec<VoidNumber>;
}

impl ledger::Connection<Config> for LedgerConnection {
type PushResponse = bool;
type Error = Infallible;

Expand Down
5 changes: 5 additions & 0 deletions manta-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ pub use sealed::*;
#[doc(inline)]
pub use serde;

#[cfg(feature = "serde_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde_with")))]
#[doc(inline)]
pub use serde_with;

/// Implements [`From`]`<$from>` for an enum `$to`, choosing the `$kind` variant.
// TODO: add `where` clauses
#[macro_export]
Expand Down