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

added source control support to wasm planner #3387

Merged
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
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?);