Skip to content

Commit

Permalink
Merge pull request #92 from panleone/handle_block_performance
Browse files Browse the repository at this point in the history
Make handle_transaction explicitly return the new decrypted notes
  • Loading branch information
Duddino authored Oct 27, 2024
2 parents 3400f21 + 2410f2c commit b40814e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 37 deletions.
31 changes: 16 additions & 15 deletions js/pivx_shield.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface Block {

interface TransactionResult {
decrypted_notes: [Note, string][];
decrypted_new_notes: [Note, string][];
commitment_tree: string;
nullifiers: string[];
}
Expand Down Expand Up @@ -316,15 +317,14 @@ export class PIVXShield {
);
}
for (const tx of block.txs) {
const { belongToWallet, decryptedNotes } = await this.decryptTransaction(
const { belongToWallet, decryptedNewNotes } = await this.addTransaction(
tx.hex,
);
await this.addTransaction(tx.hex);
if (belongToWallet) {
walletTransactions.push(tx.hex);
}
// Add all the decryptedNotes to the Nullifier->Note map
for (const note of decryptedNotes) {
for (const note of decryptedNewNotes) {
const nullifier = await this.generateNullifierFromNote(note);
const simplifiedNote = {
value: note[0].value,
Expand Down Expand Up @@ -361,7 +361,7 @@ export class PIVXShield {
);
}
async decryptTransactionOutputs(hex: string) {
const { decryptedNotes } = await this.decryptTransaction(hex);
const decryptedNotes = await this.decryptTransaction(hex);
const simplifiedNotes = [];
for (const [note, _] of decryptedNotes) {
simplifiedNotes.push({
Expand All @@ -381,11 +381,20 @@ export class PIVXShield {
this.unspentNotes,
);
this.commitmentTree = res.commitment_tree;
this.unspentNotes = res.decrypted_notes;
this.unspentNotes = res.decrypted_notes.concat(res.decrypted_new_notes);

if (res.nullifiers.length > 0) {
await this.removeSpentNotes(res.nullifiers);
}
// Check if the transaction belongs to the wallet:
let belongToWallet = res.decrypted_new_notes.length > 0;
for (const nullifier of res.nullifiers) {
if (belongToWallet) {
break;
}
belongToWallet = belongToWallet || this.mapNullifierNote.has(nullifier);
}
return { belongToWallet, decryptedNewNotes: res.decrypted_new_notes };
}

async decryptTransaction(hex: string) {
Expand All @@ -397,15 +406,7 @@ export class PIVXShield {
this.isTestnet,
[],
);
// Check if the transaction belongs to the wallet:
let belongToWallet = res.decrypted_notes.length > 0;
for (const nullifier of res.nullifiers) {
if (belongToWallet) {
break;
}
belongToWallet = belongToWallet || this.mapNullifierNote.has(nullifier);
}
return { belongToWallet, decryptedNotes: res.decrypted_notes };
return res.decrypted_new_notes;
}

/**
Expand Down Expand Up @@ -474,7 +475,7 @@ export class PIVXShield {
if (useShieldInputs) {
this.pendingSpentNotes.set(txid, nullifiers);
}
const { decryptedNotes } = await this.decryptTransaction(txhex);
const decryptedNotes = await this.decryptTransaction(txhex);
this.pendingUnspentNotes.set(
txid,
decryptedNotes.map((n) => n[0]),
Expand Down
46 changes: 33 additions & 13 deletions src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ pub async fn load_prover() -> bool {
#[derive(Serialize, Deserialize)]
pub struct JSTxSaplingData {
pub decrypted_notes: Vec<(Note, String)>,
pub decrypted_new_notes: Vec<(Note, String)>,
pub nullifiers: Vec<String>,
pub commitment_tree: String,
}
Expand Down Expand Up @@ -156,17 +157,21 @@ pub fn handle_transaction(
(note, IncrementalWitness::read(wit).unwrap())
})
.collect::<Vec<_>>();
let nullifiers = handle_transaction_internal(&mut tree, tx, key, true, &mut comp_note)
.map_err(|_| "Cannot decode tx")?;
let mut ser_comp_note: Vec<(Note, String)> = vec![];
let mut new_comp_note: Vec<(Note, IncrementalWitness<Node>)> = vec![];
let nullifiers = handle_transaction_internal(
&mut tree,
tx,
key,
true,
&mut comp_note,
&mut new_comp_note,
)
.map_err(|_| "Cannot decode tx")?;
let ser_comp_note: Vec<(Note, String)> =
serialize_comp_note(comp_note).map_err(|_| "Cannot serialize notes")?;
let ser_new_comp_note: Vec<(Note, String)> =
serialize_comp_note(new_comp_note).map_err(|_| "Cannot serialize notes")?;
let mut ser_nullifiers: Vec<String> = vec![];
for (note, witness) in comp_note {
let mut buff = Vec::new();
witness
.write(&mut buff)
.map_err(|_| "Cannot write witness to buffer")?;
ser_comp_note.push((note, hex::encode(&buff)));
}

for nullif in nullifiers.iter() {
ser_nullifiers.push(hex::encode(nullif.0));
Expand All @@ -178,19 +183,35 @@ pub fn handle_transaction(

let res: JSTxSaplingData = JSTxSaplingData {
decrypted_notes: ser_comp_note,
decrypted_new_notes: ser_new_comp_note,
nullifiers: ser_nullifiers,
commitment_tree: hex::encode(buff),
};
Ok(serde_wasm_bindgen::to_value(&res).map_err(|_| "Cannot serialize tx output")?)
}

pub fn serialize_comp_note(
comp_note: Vec<(Note, IncrementalWitness<Node>)>,
) -> Result<Vec<(Note, String)>, Box<dyn Error>> {
let mut ser_comp_note: Vec<(Note, String)> = vec![];
for (note, witness) in comp_note {
let mut buff = Vec::new();
witness
.write(&mut buff)
.map_err(|_| "Cannot write witness to buffer")?;
ser_comp_note.push((note, hex::encode(&buff)));
}
Ok(ser_comp_note)
}

//add a tx to a given commitment tree and the return a witness to each output
pub fn handle_transaction_internal(
tree: &mut CommitmentTree<Node>,
tx: &str,
key: UnifiedFullViewingKey,
is_testnet: bool,
witnesses: &mut Vec<(Note, IncrementalWitness<Node>)>,
new_witnesses: &mut Vec<(Note, IncrementalWitness<Node>)>,
) -> Result<Vec<Nullifier>, Box<dyn Error>> {
let tx = Transaction::read(
Cursor::new(hex::decode(tx)?),
Expand All @@ -210,10 +231,9 @@ pub fn handle_transaction_internal(
}

for (i, out) in sapling.shielded_outputs().iter().enumerate() {
println!("note found!");
tree.append(Node::from_cmu(out.cmu()))
.map_err(|_| "Failed to add cmu to tree")?;
for (_, witness) in witnesses.iter_mut() {
for (_, witness) in witnesses.iter_mut().chain(new_witnesses.iter_mut()) {
witness
.append(Node::from_cmu(out.cmu()))
.map_err(|_| "Failed to add cmu to witness")?;
Expand All @@ -222,7 +242,7 @@ pub fn handle_transaction_internal(
if note.index == i {
// Save witness
let witness = IncrementalWitness::from_tree(tree);
witnesses.push((decrypted_tx.swap_remove(index).note, witness));
new_witnesses.push((decrypted_tx.swap_remove(index).note, witness));
break;
}
}
Expand Down
26 changes: 17 additions & 9 deletions src/transaction/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ fn check_tx_decryption() {
let tx = "0300000001a7d31ea039ab2a9914be2a84b6e8966758da5f8d1a64ac6fb49d2763dccc38da000000006b483045022100bb67345313edea3c7462c463ea8e03ef3b14caccfbefff9877ef246138427b6a02200b74211e1f27be080561c3985980e6b0e2e833f0751ea68dfb1e465b994afefc0121025c6802ec58464d8e65d5f01be0b7ce6e8404e4a99f28ea3bfe47efe40df9108cffffffff01e8657096050000001976a914b4f73d5c66d999699a4c38ba9fe851d7141f1afa88ac0000000001003665c4ffffffff00010b39ab5d98de6f5e3f50f3f075f61fea263b4cdd6927a53ac92c196be72911237f5041af34fed06560b8620e16652edf6d297d14a9cff2145731de6643d4bf13e189dbc4b6c4b91fe421133a2f257e5b516efd9b080814251ec0169fabdac1ce4a14575d3a42a7ca852c1ef6f6e1f3daf60e9ae4b77ef4d9a589dcbc09e8437fc28e80d6a0c4f1627b3e34ee9dd5cd587d1d57bab30e0a2eba893a6b61d7e53f5b49b4cb67a807e5db203b76744025d8395c83be2eb71009f9b82e78e7b65d9740340106ee59b22cd3628f1f10c3712c2b4f86464b627b27910cd3e0a80c5387798db4f15f751b5886beb1ab1a8c298185ed6f5d3a074689ba6e327e8dc2bd3b41790ecbe0240f909b8735b8ac98a59855b448e9f37d31d5d25b71959264c145abd15f0606ab5844391819afd4017890696272abad451dab8654d76e41c389941f0fd134d7d6e3b971b15cc63ba9bea421383639bdbeaa970636d637a1c6167154f39ded089d0f07776c58e8e86c0dac8259d22644e9d8a89456e9ccf2f66ce8633a9055f1703669c6a7b009865347ef608cb4ba8f3158e05947580ec50c32f69c0079dff58b3b53367f43490d4bcaba946ef4c42b4d366c66184f84ec442499a056b6b60eeaee94151459ac0b61eb6debfa96554bbe8ec39d2c49ee6eca48ed8dc137f84584803e2372ec35e0f9f4252beef9170419e703183fa87e7d35c2403b41700bc9f5d69da6c01c870515694f5c48372cba6bacd6a79ca1cdb85f38841f7680d0dd6853b22fc95d6e307419271edb05f2f40733c31c6f827eca592658716c5c73a9dd00a7e387250beffaa78bd1f104e031e00f014f9a50935864e11ffd655ea4d4c6c3d80b681e7581a19b2668c00528110ee5322add9dacb35b519280812050061788884cad7cc409a9261e86485cc4f2d904bdf40b3c78208a395a2488eb938b8a198b51ac418fa79e5d1d7bd8f96fe0910fe61136d8fe302f144745a988d6de83e89cd8befef8a762103aa32a14d93e3ac41b44188ab385b65c1f21cf29f19a6d2af556385dd60a994ecd1ac909488f7abce29e26690651a389d4466a9e20b7f08bfbdf4f4aa3e1577dc7debf1951688db8c75347d01e836f7816df3c7a7aaa833cbd6309d179d5dfc34045e52984cf475890f04b2ffcdf123175cc07568d08d9b8525ad9eabad231e1549a19fdce0fbb30c1fe7ec59bf8ed8e642ec6571456bdba8ade4458cffb1d65fee35242d7409de14a21514416a68e9c2d5c21eb9ca5813e1d8162a48d650ed7696b7b14b4f3d3f5eb892cf32614f62dea794e7f68e6d3d3ae6edf22e811f85e1ac7fe2a8437bdf287aa4d5ff842173039074516304042370a4e2feeb901319665ffc9b005b37c2afbea22faca316ea4f6b5f365fe46f679581966dadd029d687d2b400201";
let key = UnifiedFullViewingKey::new(Some(skey.to_diversifiable_full_viewing_key()), None)
.expect("Failed to create key");
let mut comp_note = vec![];
let nullifiers = handle_transaction_internal(&mut tree, tx, key, true, &mut comp_note).unwrap();
let mut new_comp_note = vec![];
let nullifiers =
handle_transaction_internal(&mut tree, tx, key, true, &mut vec![], &mut new_comp_note)
.unwrap();
//This was a t-s tx
assert_eq!(nullifiers.len(), 0);
//Successfully decrypt exactly 1 note
assert_eq!(comp_note.len(), 1);
let note = &comp_note[0].0;
assert_eq!(new_comp_note.len(), 1);
let note = &new_comp_note[0].0;
//Successfully decrypt the balance
assert_eq!(note.value().inner(), 1000000000);
//Successfully decrypt the payment address
Expand Down Expand Up @@ -83,11 +85,17 @@ pub async fn test_create_transaction() -> Result<(), Box<dyn Error>> {
let output = "yAHuqx6mZMAiPKeV35C11Lfb3Pqxdsru5D";
let input_tx = "0300000001a347f398c8957afee7ef0fae759ff29feda25f3e72ab5052ea09729389fd48ca000000006b483045022100c332effdceaa20b3225d52d20059e443ed112d561329b81f78a9db338637e6a102204f948d70c37bfe96bbe776f8279ad5fa857c638338d8ce49f553a3ec60993d8f0121025c6802ec58464d8e65d5f01be0b7ce6e8404e4a99f28ea3bfe47efe40df9108cffffffff01e89bd55a050000001976a9147888a1affe25e5c7af03fffdbea29f13ee1be22b88ac0000000001006cca88ffffffff000150585de8e31e6c65dfa07981275f13ebb8c9c67d8c7d088622aacca6c35c67a23642ad16653acda3cf9b5230f652592197e578ea1eae78c2496a3dc274a4ba0b522216af4c44abd4e9b81964d0a801929df1cb543c4fea041d056cc493b2f8dd90db662a0a43dae4d80a8cb0bd93e22b7000c0bcdab93f94800b88268a78a4d77147f2f16bde98b2386e5ac4025260df5f63adaef13bc8d7a920dbd14fa7e8ef0c5ff29f00942341e29b15509bfa99b4b1bd0ba29c5cf2c419113c27288b3a8d8f4919a4845e47d4e5fe1d1081a98e0ee49bb0e422b339e949276a1264c236850d9beb94c7855143a4f00689d1bf8d996eee9f0ee865ca780713f5aa1990aa848d47a39ea45c926141a1ff5a5a45c2e2e78d470a180e02b3dd47e0b206a4542d4dbfc540023ee5cb35e54a086942657232c27a15c87eef6dd11587e871ea690a45002e0b60605d7c4ac7fde81a71aadde9d0cc0d5c347fbe942993bd2a69ca2ca98ea0885454e7387d609192094bea075b96f020a8ed7080b5ef0aaf13e73da67a68e377db62720724e8c0d2913487be2a3e39380b33a90f0336f07fa031345a42784460356987da3227bd40a8cf933e4b8661020cf566af785a5c9b404c84153a69d9280739cb567c6cdf41f7a1a38b4d5847b33956b4dfa847b386850eff2a3e9fe7434fb551d1c6d31fae868a2f491ebd4f382a0ac203652f4be9fb3cff3ed10e6295639af76a41e40e562862d4359e4874b565aa1bae4b68abb0a7fe66884b75250d16276521925ead4821c7f04338286c2e52e7772f980d7a228ad2b89c18c8eeaf3ee1b4d5c5a959fc93c1cda3f9340f8256a88076b96a8718efc5dcb3733e3e11f6ca1198a97a248ff4ab0a7e883e360b8495470badc7ec75f84e58d87ff83d03c594a11b9029177efa5fea026a71c2c328a6356bd447eb154ac39e43963118033fc1a72702b12e641e7dfa8f98a58e43d75f6b3350af9fc54e683c6074cfd76e86752d7f598b6816696a4f17ba5f10c983ad2f8e102f44f42b2d07b24fb599abbfd067373c4b00f9ae830fcdd79ca8fa8c90eb414f8f5bb070d1199b9e9fae7124772865e0d6f486d7f10f073a0d61bd9e8c94b7a963c831e76b5c07cef22c06877a683aca53396289b115f8b59989f3d5906c4961891ef4677ce73d752ee0ba8929056f38d7630b02db2188d512d733126fa2479217dcd5ed4061928e5ba374300d7a5fa08af2b64cbf5a2176e07b3a4a5bb4812c46c2e608d364d8589225f9b7620116e0cd6a175ab397d295ff0ee0100d2415db6c6736a0f6e2248a62c4c47b39103f67e30814cf3c9b0b82936546d4b81826cd8fdebe24ae91a81b69e7188f4b18c3422d61b367bc4ca92f8815c0fc42caf524b3337a8b9a6737557e1d471745e02a8e88a19fe730e224126d290a";

let mut notes = vec![];
let _nullifiers =
handle_transaction_internal(&mut commitment_tree, input_tx, key, true, &mut notes)?;
assert_eq!(notes.len(), 1);
let (note, path) = &notes[0];
let mut new_notes = vec![];
let _nullifiers = handle_transaction_internal(
&mut commitment_tree,
input_tx,
key,
true,
&mut vec![],
&mut new_notes,
)?;
assert_eq!(new_notes.len(), 1);
let (note, path) = &new_notes[0];
let mut path_vec = vec![];
path.write(&mut path_vec)?;
let path = hex::encode(path_vec);
Expand Down

0 comments on commit b40814e

Please sign in to comment.