Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.

Commit c19c5b6

Browse files
committed
multiple notes in same tx test
1 parent 6972c99 commit c19c5b6

File tree

2 files changed

+133
-8
lines changed

2 files changed

+133
-8
lines changed

lib/src/blaze/test_utils.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ impl FakeCompactBlock {
8787
Self { block: cb, height }
8888
}
8989

90-
pub fn add_tx(&mut self, ctx: CompactTx) {
91-
self.block.vtx.push(ctx);
90+
pub fn add_txs(&mut self, ctxs: Vec<CompactTx>) {
91+
self.block.vtx.extend(ctxs);
9292
}
9393

9494
// Add a new tx into the block, paying the given address the amount.
@@ -183,22 +183,21 @@ impl FakeCompactBlockList {
183183
data.write().await.add_txns(vec![(tx.clone(), new_block.height)]);
184184

185185
ctx.hash = tx.txid().0.to_vec();
186-
new_block.add_tx(ctx);
186+
new_block.add_txs(vec![ctx]);
187187
}
188188
}
189189

190190
// Add a new tx into the block, paying the given address the amount.
191191
// Returns the nullifier of the new note.
192192
pub fn add_tx_paying(&mut self, extfvk: &ExtendedFullViewingKey, value: u64) -> (Nullifier, Transaction, u64) {
193193
let to = extfvk.default_address().unwrap().1;
194-
let value = Amount::from_u64(value).unwrap();
195194

196195
// Create a fake Note for the account
197196
let mut rng = OsRng;
198197
let note = Note {
199198
g_d: to.diversifier().g_d().unwrap(),
200199
pk_d: to.pk_d().clone(),
201-
value: value.into(),
200+
value,
202201
rseed: Rseed::BeforeZip212(jubjub::Fr::random(rng)),
203202
};
204203
let nf = note.nf(&extfvk.fvk.vk, 0);
@@ -209,7 +208,7 @@ impl FakeCompactBlockList {
209208
let mut rng = OsRng;
210209
let rcv = jubjub::Fr::random(&mut rng);
211210
let cv = ValueCommitment {
212-
value: value.into(),
211+
value,
213212
randomness: rcv.clone(),
214213
};
215214

@@ -246,7 +245,7 @@ impl FakeCompactBlockList {
246245
ctx.hash = tx.txid().clone().0.to_vec();
247246
ctx.outputs.push(cout);
248247

249-
self.add_empty_block().add_tx(ctx);
248+
self.add_empty_block().add_txs(vec![ctx]);
250249

251250
(nf, tx, height)
252251
}

lib/src/lightclient/tests.rs

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
use std::sync::Arc;
22

3+
use ff::{Field, PrimeField};
34
use futures::FutureExt;
5+
use group::GroupEncoding;
46
use json::JsonValue;
7+
use jubjub::ExtendedPoint;
58
use portpicker;
9+
use rand::rngs::OsRng;
610
use tempdir::TempDir;
711
use tokio::sync::{oneshot, RwLock};
812
use tokio::task::JoinHandle;
913
use tonic::transport::{Channel, Server};
1014
use tonic::Request;
1115

16+
use zcash_primitives::memo::Memo;
17+
use zcash_primitives::note_encryption::SaplingNoteEncryption;
18+
use zcash_primitives::primitives::{Note, Rseed, ValueCommitment};
19+
use zcash_primitives::redjubjub::Signature;
20+
use zcash_primitives::transaction::components::{OutputDescription, GROTH_PROOF_SIZE};
21+
use zcash_primitives::transaction::TransactionData;
22+
1223
use crate::blaze::test_utils::FakeCompactBlockList;
1324
use crate::compact_formats::compact_tx_streamer_client::CompactTxStreamerClient;
1425
use crate::compact_formats::compact_tx_streamer_server::CompactTxStreamerServer;
15-
use crate::compact_formats::Empty;
26+
use crate::compact_formats::{CompactOutput, CompactTx, Empty};
1627
use crate::lightclient::lightclient_config::LightClientConfig;
1728
use crate::lightclient::test_server::TestGRPCService;
1829
use crate::lightclient::LightClient;
@@ -248,4 +259,119 @@ async fn z_incoming_z_outgoing() {
248259
h1.await.unwrap();
249260
}
250261

262+
#[tokio::test]
263+
async fn multiple_incoming_same_tx() {
264+
let (data, config, ready_rx, stop_tx, h1) = create_test_server().await;
265+
266+
ready_rx.await.unwrap();
267+
268+
let lc = LightClient::test_new(&config, None).await.unwrap();
269+
let mut fcbl = FakeCompactBlockList::new(0);
270+
271+
let extfvk1 = lc.wallet.keys().read().await.get_all_extfvks()[0].clone();
272+
let value = 100_000;
273+
274+
// 1. Mine 100 blocks
275+
mine_random_blocks(&mut fcbl, &data, &lc, 100).await;
276+
assert_eq!(lc.wallet.last_scanned_height().await, 100);
277+
278+
// 2. Construct the Fake tx.
279+
let to = extfvk1.default_address().unwrap().1;
280+
281+
// Create fake note for the account
282+
let mut ctx = CompactTx::default();
283+
let mut td = TransactionData::new();
284+
285+
// Add 4 outputs
286+
for i in 0..4 {
287+
let mut rng = OsRng;
288+
let value = value + i;
289+
let note = Note {
290+
g_d: to.diversifier().g_d().unwrap(),
291+
pk_d: to.pk_d().clone(),
292+
value,
293+
rseed: Rseed::BeforeZip212(jubjub::Fr::random(rng)),
294+
};
295+
296+
let mut encryptor =
297+
SaplingNoteEncryption::new(None, note.clone(), to.clone(), Memo::default().into(), &mut rng);
298+
299+
let mut rng = OsRng;
300+
let rcv = jubjub::Fr::random(&mut rng);
301+
let cv = ValueCommitment {
302+
value,
303+
randomness: rcv.clone(),
304+
};
305+
306+
let cmu = note.cmu();
307+
let od = OutputDescription {
308+
cv: cv.commitment().into(),
309+
cmu: note.cmu(),
310+
ephemeral_key: ExtendedPoint::from(*encryptor.epk()),
311+
enc_ciphertext: encryptor.encrypt_note_plaintext(),
312+
out_ciphertext: encryptor.encrypt_outgoing_plaintext(&cv.commitment().into(), &cmu),
313+
zkproof: [0; GROTH_PROOF_SIZE],
314+
};
315+
316+
let mut cmu = vec![];
317+
cmu.extend_from_slice(&note.cmu().to_repr());
318+
let mut epk = vec![];
319+
epk.extend_from_slice(&encryptor.epk().to_bytes());
320+
let enc_ciphertext = encryptor.encrypt_note_plaintext();
321+
322+
// Create a fake CompactBlock containing the note
323+
let mut cout = CompactOutput::default();
324+
cout.cmu = cmu;
325+
cout.epk = epk;
326+
cout.ciphertext = enc_ciphertext[..52].to_vec();
327+
ctx.outputs.push(cout);
328+
329+
td.shielded_outputs.push(od);
330+
td.binding_sig = Signature::read(&vec![0u8; 64][..]).ok();
331+
}
332+
333+
let tx = td.freeze().unwrap();
334+
ctx.hash = tx.txid().clone().0.to_vec();
335+
336+
// Add and mine the block
337+
fcbl.txns.push((tx.clone(), fcbl.next_height));
338+
fcbl.add_empty_block().add_txs(vec![ctx]);
339+
mine_pending_blocks(&mut fcbl, &data, &lc).await;
340+
assert_eq!(lc.wallet.last_scanned_height().await, 101);
341+
342+
// 2. Check the notes - that we recieved 4 notes
343+
let notes = lc.do_list_notes(true).await;
344+
for i in 0..4 {
345+
assert_eq!(notes["unspent_notes"][i]["created_in_block"].as_u64().unwrap(), 101);
346+
assert_eq!(notes["unspent_notes"][i]["value"].as_u64().unwrap(), value + i as u64);
347+
assert_eq!(notes["unspent_notes"][i]["is_change"].as_bool().unwrap(), false);
348+
assert_eq!(
349+
notes["unspent_notes"][i]["address"],
350+
lc.wallet.keys().read().await.get_all_zaddresses()[0]
351+
);
352+
}
353+
354+
// 3. Send a big tx, so all the value is spent
355+
let sent_value = value * 3 + 1000;
356+
mine_random_blocks(&mut fcbl, &data, &lc, 5).await; // make the funds spentable
357+
let sent_txid = lc.test_do_send(vec![(EXT_ZADDR, sent_value, None)]).await.unwrap();
358+
359+
// 4. Mine the sent transaction
360+
fcbl.add_pending_sends(&data).await;
361+
mine_pending_blocks(&mut fcbl, &data, &lc).await;
362+
363+
println!("{}", lc.do_list_notes(true).await.pretty(2));
364+
365+
// 5. Check the notes - that we recieved 4 notes
366+
let notes = lc.do_list_notes(true).await;
367+
for i in 0..4 {
368+
assert_eq!(notes["spent_notes"][i]["spent"], sent_txid);
369+
assert_eq!(notes["spent_notes"][i]["spent_at_height"].as_u64().unwrap(), 107);
370+
}
371+
372+
// Shutdown everything cleanly
373+
stop_tx.send(true).unwrap();
374+
h1.await.unwrap();
375+
}
376+
251377
const EXT_ZADDR: &str = "zs1va5902apnzlhdu0pw9r9q7ca8s4vnsrp2alr6xndt69jnepn2v2qrj9vg3wfcnjyks5pg65g9dc";

0 commit comments

Comments
 (0)