Skip to content

Commit

Permalink
Showing 3 changed files with 47 additions and 27 deletions.
10 changes: 7 additions & 3 deletions crates/wasm/src/planner.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ use penumbra_governance::{
use penumbra_ibc::IbcRelay;
use penumbra_keys::Address;
use penumbra_num::Amount;
use penumbra_proto::core::keys::v1alpha1::AddressIndex;
use penumbra_proto::view::v1alpha1::{NotesForVotingRequest, NotesRequest};
use penumbra_shielded_pool::{Ics20Withdrawal, Note, OutputPlan, SpendPlan};
use penumbra_stake::{rate::RateData, validator};
@@ -94,14 +95,17 @@ impl<R: RngCore + CryptoRng> Planner<R> {
}

/// Get all the note requests necessary to fulfill the current [`Balance`].
pub fn notes_requests(&self) -> (Vec<NotesRequest>, Vec<NotesForVotingRequest>) {
pub fn notes_requests(
&self,
source: Option<AddressIndex>,
) -> (Vec<NotesRequest>, Vec<NotesForVotingRequest>) {
(
self.balance
.required()
.map(|Value { asset_id, amount }| NotesRequest {
wallet_id: None,
asset_id: Some(asset_id.into()),
address_index: None,
address_index: source.clone(),
amount_to_spend: Some(amount.into()),
include_spent: false,
})
@@ -117,7 +121,7 @@ impl<R: RngCore + CryptoRng> Planner<R> {
)| NotesForVotingRequest {
wallet_id: None,
votable_at_height: *start_block_height,
address_index: None,
address_index: source.clone(),
},
)
.collect(),
52 changes: 32 additions & 20 deletions crates/wasm/src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use indexed_db_futures::prelude::OpenDbRequest;
use indexed_db_futures::{IdbDatabase, IdbQuerySource};
use serde::{Deserialize, Serialize};
use wasm_bindgen::JsValue;
use web_sys::IdbTransactionMode::Readwrite;

use penumbra_asset::asset::{DenomMetadata, Id};
@@ -10,7 +11,7 @@ use penumbra_proto::DomainType;
use penumbra_sct::Nullifier;
use penumbra_shielded_pool::{note, Note};

use crate::error::WasmResult;
use crate::error::{WasmError, WasmResult};
use crate::note_record::SpendableNoteRecord;

#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -46,28 +47,39 @@ impl IndexedDBStorage {
.transaction_on_one(&self.constants.tables.spendable_notes)?;
let store = idb_tx.object_store(&self.constants.tables.spendable_notes)?;

let values = store.get_all()?.await?;

let notes: Vec<SpendableNoteRecord> = values
let raw_values = store.get_all()?.await?;
let parsed_notes = raw_values
.into_iter()
.map(|js_value| serde_wasm_bindgen::from_value(js_value).ok())
.filter_map(|note_option| {
note_option.and_then(|note: SpendableNoteRecord| match request.asset_id.clone() {
Some(asset_id) => {
if note.note.asset_id() == asset_id.try_into().expect("Invalid asset id")
&& note.height_spent.is_none()
{
Some(note)
} else {
None
}
}
None => Some(note),
})
})
.filter_map(|js_value| self.parse_note(js_value, &request).ok())
.collect();

Ok(notes)
Ok(parsed_notes)
}

fn parse_note(
&self,
js_value: JsValue,
request: &NotesRequest,
) -> WasmResult<SpendableNoteRecord> {
let note: SpendableNoteRecord = serde_wasm_bindgen::from_value(js_value)?;

let asset_id_matches = match &request.asset_id {
Some(asset_id) => note.note.asset_id() == asset_id.clone().try_into()?,
None => true,
};

let address_index_matches = match &request.address_index {
Some(address_index) => note.address_index.eq(&address_index.clone().try_into()?),
None => true,
};

if asset_id_matches && address_index_matches && note.height_spent.is_none() {
Ok(note)
} else {
Err(WasmError::Anyhow(anyhow::anyhow!(
"Note does not match the request"
)))
}
}

pub async fn get_asset(&self, id: &Id) -> WasmResult<Option<DenomMetadata>> {
12 changes: 8 additions & 4 deletions crates/wasm/src/wasm_planner.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use penumbra_dex::swap_claim::SwapClaimPlan;
use penumbra_proto::core::asset::v1alpha1::{DenomMetadata, Value};
use penumbra_proto::core::component::fee::v1alpha1::{Fee, GasPrices};
use penumbra_proto::core::component::ibc::v1alpha1::Ics20Withdrawal;
use penumbra_proto::core::keys::v1alpha1::Address;
use penumbra_proto::core::keys::v1alpha1::{Address, AddressIndex};
use penumbra_proto::core::transaction::v1alpha1::MemoPlaintext;
use penumbra_proto::crypto::tct::v1alpha1::StateCommitment;
use penumbra_proto::DomainType;
@@ -184,11 +184,13 @@ impl WasmPlanner {
}

/// Builds transaction plan.
/// Refund address provided in the case there is extra balances to be returned.
/// Refund address provided in the case there is extra balances to be returned
// If source present, only spends funds from the given account.
/// Arguments:
/// refund_address: `Address`
/// source: `Option<AddressIndex>`
/// Returns: `TransactionPlan`
pub async fn plan(&mut self, refund_address: JsValue) -> WasmResult<JsValue> {
pub async fn plan(&mut self, refund_address: JsValue, source: JsValue) -> WasmResult<JsValue> {
utils::set_panic_hook();

// Calculate the gas that needs to be paid for the transaction based on the configured gas prices.
@@ -199,7 +201,9 @@ impl WasmPlanner {

let mut spendable_notes = Vec::new();

let (spendable_requests, _) = self.planner.notes_requests();
let source_address_index: Option<AddressIndex> = serde_wasm_bindgen::from_value(source)?;

let (spendable_requests, _) = self.planner.notes_requests(source_address_index);
for request in spendable_requests {
let notes = self.storage.get_notes(request);
spendable_notes.extend(notes.await?);

0 comments on commit 832428f

Please sign in to comment.