Merge pull request #309 from nuttycom/test_utils
Make transaction builder more useful for testing.
This commit is contained in:
commit
04a2bd4ad8
|
@ -237,7 +237,7 @@ pub fn prf_ock(
|
|||
/// let encCiphertext = enc.encrypt_note_plaintext();
|
||||
/// let outCiphertext = enc.encrypt_outgoing_plaintext(&cv.commitment().into(), &cmu);
|
||||
/// ```
|
||||
pub struct SaplingNoteEncryption<R: RngCore + CryptoRng> {
|
||||
pub struct SaplingNoteEncryption<R: RngCore> {
|
||||
epk: jubjub::SubgroupPoint,
|
||||
esk: jubjub::Fr,
|
||||
note: Note,
|
||||
|
@ -254,13 +254,25 @@ impl<R: RngCore + CryptoRng> SaplingNoteEncryption<R> {
|
|||
/// Setting `ovk` to `None` represents the `ovk = ⊥` case, where the note cannot be
|
||||
/// recovered by the sender.
|
||||
pub fn new(
|
||||
ovk: Option<OutgoingViewingKey>,
|
||||
note: Note,
|
||||
to: PaymentAddress,
|
||||
memo: Memo,
|
||||
rng: R,
|
||||
) -> Self {
|
||||
Self::new_internal(ovk, note, to, memo, rng)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: RngCore> SaplingNoteEncryption<R> {
|
||||
pub(crate) fn new_internal(
|
||||
ovk: Option<OutgoingViewingKey>,
|
||||
note: Note,
|
||||
to: PaymentAddress,
|
||||
memo: Memo,
|
||||
mut rng: R,
|
||||
) -> Self {
|
||||
let esk = note.generate_or_derive_esk(&mut rng);
|
||||
let esk = note.generate_or_derive_esk_internal(&mut rng);
|
||||
let epk = note.g_d * esk;
|
||||
|
||||
SaplingNoteEncryption {
|
||||
|
|
|
@ -292,6 +292,10 @@ impl Note {
|
|||
}
|
||||
|
||||
pub fn generate_or_derive_esk<R: RngCore + CryptoRng>(&self, rng: &mut R) -> jubjub::Fr {
|
||||
self.generate_or_derive_esk_internal(rng)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_or_derive_esk_internal<R: RngCore>(&self, rng: &mut R) -> jubjub::Fr {
|
||||
match self.derive_esk() {
|
||||
None => {
|
||||
// create random 64 byte buffer
|
||||
|
|
|
@ -59,7 +59,7 @@ pub trait TxProver {
|
|||
) -> Result<Signature, ()>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
pub mod mock {
|
||||
use ff::Field;
|
||||
use rand_core::OsRng;
|
||||
|
@ -78,9 +78,8 @@ pub mod mock {
|
|||
|
||||
use super::TxProver;
|
||||
|
||||
pub(crate) struct MockTxProver;
|
||||
pub struct MockTxProver;
|
||||
|
||||
#[cfg(test)]
|
||||
impl TxProver for MockTxProver {
|
||||
type SaplingProvingContext = ();
|
||||
|
||||
|
|
|
@ -114,6 +114,15 @@ pub fn spend_sig<R: RngCore + CryptoRng>(
|
|||
ar: jubjub::Fr,
|
||||
sighash: &[u8; 32],
|
||||
rng: &mut R,
|
||||
) -> Signature {
|
||||
spend_sig_internal(ask, ar, sighash, rng)
|
||||
}
|
||||
|
||||
pub(crate) fn spend_sig_internal<R: RngCore>(
|
||||
ask: PrivateKey,
|
||||
ar: jubjub::Fr,
|
||||
sighash: &[u8; 32],
|
||||
rng: &mut R,
|
||||
) -> Signature {
|
||||
// We compute `rsk`...
|
||||
let rsk = ask.randomize(ar);
|
||||
|
|
|
@ -19,14 +19,14 @@ use crate::{
|
|||
primitives::{Diversifier, Note, PaymentAddress},
|
||||
prover::TxProver,
|
||||
redjubjub::PrivateKey,
|
||||
sapling::{spend_sig, Node},
|
||||
sapling::{spend_sig_internal, Node},
|
||||
transaction::{
|
||||
components::{
|
||||
amount::Amount, amount::DEFAULT_FEE, OutputDescription, SpendDescription, TxOut,
|
||||
},
|
||||
signature_hash_data, SignableInput, Transaction, TransactionData, SIGHASH_ALL,
|
||||
},
|
||||
util::generate_random_rseed,
|
||||
util::generate_random_rseed_internal,
|
||||
zip32::ExtendedSpendingKey,
|
||||
};
|
||||
|
||||
|
@ -42,6 +42,10 @@ use crate::{
|
|||
#[cfg(any(feature = "transparent-inputs", feature = "zfuture"))]
|
||||
use crate::transaction::components::OutPoint;
|
||||
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
use crate::prover::mock::MockTxProver;
|
||||
|
||||
|
||||
const DEFAULT_TX_EXPIRY_DELTA: u32 = 20;
|
||||
|
||||
/// If there are any shielded inputs, always have at least two shielded outputs, padding
|
||||
|
@ -107,6 +111,18 @@ impl SaplingOutput {
|
|||
to: PaymentAddress,
|
||||
value: Amount,
|
||||
memo: Option<Memo>,
|
||||
) -> Result<Self, Error> {
|
||||
Self::new_internal(params, height, rng, ovk, to, value, memo)
|
||||
}
|
||||
|
||||
fn new_internal<R: RngCore, P: consensus::Parameters>(
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
rng: &mut R,
|
||||
ovk: Option<OutgoingViewingKey>,
|
||||
to: PaymentAddress,
|
||||
value: Amount,
|
||||
memo: Option<Memo>,
|
||||
) -> Result<Self, Error> {
|
||||
let g_d = match to.g_d() {
|
||||
Some(g_d) => g_d,
|
||||
|
@ -116,7 +132,7 @@ impl SaplingOutput {
|
|||
return Err(Error::InvalidAmount);
|
||||
}
|
||||
|
||||
let rseed = generate_random_rseed(params, height, rng);
|
||||
let rseed = generate_random_rseed_internal(params, height, rng);
|
||||
|
||||
let note = Note {
|
||||
g_d,
|
||||
|
@ -139,7 +155,16 @@ impl SaplingOutput {
|
|||
ctx: &mut P::SaplingProvingContext,
|
||||
rng: &mut R,
|
||||
) -> OutputDescription {
|
||||
let mut encryptor = SaplingNoteEncryption::new(
|
||||
self.build_internal(prover, ctx, rng)
|
||||
}
|
||||
|
||||
fn build_internal<P: TxProver, R: RngCore>(
|
||||
self,
|
||||
prover: &P,
|
||||
ctx: &mut P::SaplingProvingContext,
|
||||
rng: &mut R,
|
||||
) -> OutputDescription {
|
||||
let mut encryptor = SaplingNoteEncryption::new_internal(
|
||||
self.ovk,
|
||||
self.note.clone(),
|
||||
self.to.clone(),
|
||||
|
@ -341,7 +366,7 @@ impl TransactionMetadata {
|
|||
}
|
||||
|
||||
/// Generates a [`Transaction`] from its inputs and outputs.
|
||||
pub struct Builder<'a, P: consensus::Parameters, R: RngCore + CryptoRng> {
|
||||
pub struct Builder<'a, P: consensus::Parameters, R: RngCore> {
|
||||
params: P,
|
||||
rng: R,
|
||||
height: BlockHeight,
|
||||
|
@ -423,8 +448,13 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
|
|||
pub fn new_with_rng_zfuture(params: P, height: BlockHeight, rng: R) -> Builder<'a, P, R> {
|
||||
Self::new_with_mtx(params, height, rng, TransactionData::zfuture())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
||||
/// Common utility function for builder construction.
|
||||
///
|
||||
/// WARNING: THIS MUST REMAIN PRIVATE AS IT ALLOWS CONSTRUCTION
|
||||
/// OF BUILDERS WITH NON-CryptoRng RNGs
|
||||
fn new_with_mtx(
|
||||
params: P,
|
||||
height: BlockHeight,
|
||||
|
@ -495,7 +525,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
|
|||
value: Amount,
|
||||
memo: Option<Memo>,
|
||||
) -> Result<(), Error> {
|
||||
let output = SaplingOutput::new(
|
||||
let output = SaplingOutput::new_internal(
|
||||
&self.params,
|
||||
self.height,
|
||||
&mut self.rng,
|
||||
|
@ -700,7 +730,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
|
|||
// Record the post-randomized output location
|
||||
tx_metadata.output_indices[pos] = i;
|
||||
|
||||
output.build(prover, &mut ctx, &mut self.rng)
|
||||
output.build_internal(prover, &mut ctx, &mut self.rng)
|
||||
} else {
|
||||
// This is a dummy output
|
||||
let (dummy_to, dummy_note) = {
|
||||
|
@ -727,7 +757,8 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
|
|||
}
|
||||
};
|
||||
|
||||
let rseed = generate_random_rseed(&self.params, self.height, &mut self.rng);
|
||||
let rseed =
|
||||
generate_random_rseed_internal(&self.params, self.height, &mut self.rng);
|
||||
|
||||
(
|
||||
payment_address,
|
||||
|
@ -740,7 +771,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
|
|||
)
|
||||
};
|
||||
|
||||
let esk = dummy_note.generate_or_derive_esk(&mut self.rng);
|
||||
let esk = dummy_note.generate_or_derive_esk_internal(&mut self.rng);
|
||||
let epk = dummy_note.g_d * esk;
|
||||
|
||||
let (zkproof, cv) = prover.output_proof(
|
||||
|
@ -785,7 +816,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
|
|||
|
||||
// Create Sapling spendAuth and binding signatures
|
||||
for (i, (_, spend)) in spends.into_iter().enumerate() {
|
||||
self.mtx.shielded_spends[i].spend_auth_sig = Some(spend_sig(
|
||||
self.mtx.shielded_spends[i].spend_auth_sig = Some(spend_sig_internal(
|
||||
PrivateKey(spend.extsk.expsk.ask),
|
||||
spend.alpha,
|
||||
&sighash,
|
||||
|
@ -878,6 +909,56 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> ExtensionTxBuilder<'a
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
||||
/// Creates a new `Builder` targeted for inclusion in the block with the given height
|
||||
/// and randomness source, using default values for general transaction fields.
|
||||
///
|
||||
/// # Default values
|
||||
///
|
||||
/// The expiry height will be set to the given height plus the default transaction
|
||||
/// expiry delta (20 blocks).
|
||||
///
|
||||
/// The fee will be set to the default fee (0.0001 ZEC).
|
||||
///
|
||||
/// WARNING: DO NOT USE IN PRODUCTION
|
||||
pub fn test_only_new_with_rng(params: P, height: BlockHeight, rng: R) -> Builder<'a, P, R> {
|
||||
Self::new_with_mtx(params, height, rng, TransactionData::new())
|
||||
}
|
||||
|
||||
/// Creates a new `Builder` targeted for inclusion in the block with the given height,
|
||||
/// and randomness source, using default values for general transaction fields
|
||||
/// and the `ZFUTURE_TX_VERSION` and `ZFUTURE_VERSION_GROUP_ID` version identifiers.
|
||||
///
|
||||
/// # Default values
|
||||
///
|
||||
/// The expiry height will be set to the given height plus the default transaction
|
||||
/// expiry delta (20 blocks).
|
||||
///
|
||||
/// The fee will be set to the default fee (0.0001 ZEC).
|
||||
///
|
||||
/// The transaction will be constructed and serialized according to the
|
||||
/// NetworkUpgrade::ZFuture rules. This is intended only for use in
|
||||
/// integration testing of new features.
|
||||
///
|
||||
/// WARNING: DO NOT USE IN PRODUCTION
|
||||
#[cfg(feature = "zfuture")]
|
||||
pub fn test_only_new_with_rng_zfuture(
|
||||
params: P,
|
||||
height: BlockHeight,
|
||||
rng: R,
|
||||
) -> Builder<'a, P, R> {
|
||||
Self::new_with_mtx(params, height, rng, TransactionData::zfuture())
|
||||
}
|
||||
|
||||
pub fn mock_build(
|
||||
self,
|
||||
consensus_branch_id: consensus::BranchId,
|
||||
) -> Result<(Transaction, TransactionMetadata), Error> {
|
||||
self.build(consensus_branch_id, &MockTxProver)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ff::{Field, PrimeField};
|
||||
|
|
|
@ -22,6 +22,14 @@ pub fn generate_random_rseed<P: consensus::Parameters, R: RngCore + CryptoRng>(
|
|||
params: &P,
|
||||
height: BlockHeight,
|
||||
rng: &mut R,
|
||||
) -> Rseed {
|
||||
generate_random_rseed_internal(params, height, rng)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_random_rseed_internal<P: consensus::Parameters, R: RngCore>(
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
rng: &mut R,
|
||||
) -> Rseed {
|
||||
if params.is_nu_active(NetworkUpgrade::Canopy, height) {
|
||||
let mut buffer = [0u8; 32];
|
||||
|
|
Loading…
Reference in New Issue