De-duplicate compact Sapling output creation in `TestState`

This commit is contained in:
Jack Grigg 2024-03-07 22:52:11 +00:00
parent f306a0a78a
commit bc0b1aed07
1 changed files with 63 additions and 90 deletions

View File

@ -7,7 +7,7 @@ use std::fs::File;
use nonempty::NonEmpty; use nonempty::NonEmpty;
use prost::Message; use prost::Message;
use rand_core::{OsRng, RngCore}; use rand_core::{CryptoRng, OsRng, RngCore};
use rusqlite::{params, Connection}; use rusqlite::{params, Connection};
use secrecy::{Secret, SecretVec}; use secrecy::{Secret, SecretVec};
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
@ -18,7 +18,6 @@ use tempfile::TempDir;
use sapling::{ use sapling::{
note_encryption::{sapling_note_encryption, SaplingDomain}, note_encryption::{sapling_note_encryption, SaplingDomain},
util::generate_random_rseed, util::generate_random_rseed,
value::NoteValue,
zip32::DiversifiableFullViewingKey, zip32::DiversifiableFullViewingKey,
Note, Nullifier, PaymentAddress, Note, Nullifier, PaymentAddress,
}; };
@ -765,6 +764,49 @@ pub(crate) enum AddressType {
Internal, Internal,
} }
/// Creates a `CompactSaplingOutput` at the given height paying the given recipient.
///
/// Returns the `CompactSaplingOutput` and the new note.
fn compact_sapling_output<P: consensus::Parameters, R: RngCore + CryptoRng>(
params: &P,
height: BlockHeight,
recipient: sapling::PaymentAddress,
value: NonNegativeAmount,
ovk: sapling::keys::OutgoingViewingKey,
rng: &mut R,
) -> (CompactSaplingOutput, sapling::Note) {
let rseed = generate_random_rseed(zip212_enforcement(params, height), rng);
let note = Note::from_parts(
recipient,
sapling::value::NoteValue::from_raw(value.into_u64()),
rseed,
);
let encryptor =
sapling_note_encryption(Some(ovk), note.clone(), *MemoBytes::empty().as_array(), rng);
let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext();
(
CompactSaplingOutput {
cmu,
ephemeral_key,
ciphertext: enc_ciphertext.as_ref()[..52].to_vec(),
},
note,
)
}
/// Creates a fake `CompactTx` with a random transaction ID and no spends or outputs.
fn fake_compact_tx<R: RngCore + CryptoRng>(rng: &mut R) -> CompactTx {
let mut ctx = CompactTx::default();
let mut txid = vec![0; 32];
rng.fill_bytes(&mut txid);
ctx.hash = txid;
ctx
}
/// Create a fake CompactBlock at the given height, containing a single output paying /// Create a fake CompactBlock at the given height, containing a single output paying
/// an address. Returns the CompactBlock and the nullifier for the new note. /// an address. Returns the CompactBlock and the nullifier for the new note.
fn fake_compact_block<P: consensus::Parameters>( fn fake_compact_block<P: consensus::Parameters>(
@ -784,45 +826,14 @@ fn fake_compact_block<P: consensus::Parameters>(
// Create a fake Note for the account // Create a fake Note for the account
let mut rng = OsRng; let mut rng = OsRng;
let rseed = generate_random_rseed(zip212_enforcement(params, height), &mut rng); let (cout, note) = compact_sapling_output(params, height, to, value, dfvk.fvk().ovk, &mut rng);
let note = Note::from_parts(to, NoteValue::from_raw(value.into_u64()), rseed);
let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk),
note.clone(),
*MemoBytes::empty().as_array(),
&mut rng,
);
let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext();
// Create a fake CompactBlock containing the note // Create a fake CompactBlock containing the note
let cout = CompactSaplingOutput { let mut ctx = fake_compact_tx(&mut rng);
cmu,
ephemeral_key,
ciphertext: enc_ciphertext.as_ref()[..52].to_vec(),
};
let mut ctx = CompactTx::default();
let mut txid = vec![0; 32];
rng.fill_bytes(&mut txid);
ctx.hash = txid;
ctx.outputs.push(cout); ctx.outputs.push(cout);
let mut cb = CompactBlock {
hash: { let cb =
let mut hash = vec![0; 32]; fake_compact_block_from_compact_tx(ctx, height, prev_hash, initial_sapling_tree_size, 0);
rng.fill_bytes(&mut hash);
hash
},
height: height.into(),
..Default::default()
};
cb.prev_hash.extend_from_slice(&prev_hash.0);
cb.vtx.push(ctx);
cb.chain_metadata = Some(compact::ChainMetadata {
sapling_commitment_tree_size: initial_sapling_tree_size
+ cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::<u32>(),
..Default::default()
});
(cb, note.nf(&dfvk.fvk().vk.nk, 0)) (cb, note.nf(&dfvk.fvk().vk.nk, 0))
} }
@ -880,67 +891,29 @@ fn fake_compact_block_spending<P: consensus::Parameters>(
value: NonNegativeAmount, value: NonNegativeAmount,
initial_sapling_tree_size: u32, initial_sapling_tree_size: u32,
) -> CompactBlock { ) -> CompactBlock {
let zip212_enforcement = zip212_enforcement(params, height);
let mut rng = OsRng; let mut rng = OsRng;
let rseed = generate_random_rseed(zip212_enforcement, &mut rng); let mut ctx = fake_compact_tx(&mut rng);
// Create a fake CompactBlock containing the note // Create a fake spend
let cspend = CompactSaplingSpend { nf: nf.to_vec() }; let cspend = CompactSaplingSpend { nf: nf.to_vec() };
let mut ctx = CompactTx::default();
let mut txid = vec![0; 32];
rng.fill_bytes(&mut txid);
ctx.hash = txid;
ctx.spends.push(cspend); ctx.spends.push(cspend);
// Create a fake Note for the payment // Create a fake Note for the payment
ctx.outputs.push({ ctx.outputs
let note = Note::from_parts( .push(compact_sapling_output(params, height, to, value, dfvk.fvk().ovk, &mut rng).0);
to,
sapling::value::NoteValue::from_raw(value.into_u64()),
rseed,
);
let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk),
note.clone(),
*MemoBytes::empty().as_array(),
&mut rng,
);
let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext();
CompactSaplingOutput {
cmu,
ephemeral_key,
ciphertext: enc_ciphertext.as_ref()[..52].to_vec(),
}
});
// Create a fake Note for the change // Create a fake Note for the change
ctx.outputs.push({ ctx.outputs.push(
let change_addr = dfvk.default_address().1; compact_sapling_output(
let rseed = generate_random_rseed(zip212_enforcement, &mut rng); params,
let note = Note::from_parts( height,
change_addr, dfvk.default_address().1,
NoteValue::from_raw((in_value - value).unwrap().into_u64()), (in_value - value).unwrap(),
rseed, dfvk.fvk().ovk,
);
let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk),
note.clone(),
*MemoBytes::empty().as_array(),
&mut rng, &mut rng,
)
.0,
); );
let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext();
CompactSaplingOutput {
cmu,
ephemeral_key,
ciphertext: enc_ciphertext.as_ref()[..52].to_vec(),
}
});
fake_compact_block_from_compact_tx(ctx, height, prev_hash, initial_sapling_tree_size, 0) fake_compact_block_from_compact_tx(ctx, height, prev_hash, initial_sapling_tree_size, 0)
} }