Merge pull request #361 from str4d/release-0.5-prep

Release 0.5 preparations
This commit is contained in:
str4d 2021-03-26 14:45:26 +13:00 committed by GitHub
commit 44e3176d5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 97 additions and 48 deletions

View File

@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
edition = "2018"
[dependencies]
bech32 = "0.7"
bech32 = "0.8"
bls12_381 = "0.3.1"
bs58 = { version = "0.4", features = ["check"] }
base64 = "0.13"

View File

@ -187,11 +187,21 @@ pub struct PrunedBlock<'a> {
pub transactions: &'a Vec<WalletTx<Nullifier>>,
}
/// A transaction that was detected during scanning of the blockchain,
/// including its decrypted Sapling outputs.
///
/// The purpose of this struct is to permit atomic updates of the
/// wallet database when transactions are successfully decrypted.
pub struct ReceivedTransaction<'a> {
pub tx: &'a Transaction,
pub outputs: &'a Vec<DecryptedOutput>,
}
/// A transaction that was constructed and sent by the wallet.
///
/// The purpose of this struct is to permit atomic updates of the
/// wallet database when transactions are created and submitted
/// to the network.
pub struct SentTransaction<'a> {
pub tx: &'a Transaction,
pub created: time::OffsetDateTime,

View File

@ -192,8 +192,9 @@ where
/// caller is handling rollbacks.
///
/// For brand-new light client databases, this function starts scanning from the Sapling
/// activation height. This height can be fast-forwarded to a more recent block by calling
/// [`init_blocks_table`] before this function.
/// activation height. This height can be fast-forwarded to a more recent block by
/// initializing the client database with a starting block (for example, calling
/// `init_blocks_table` before this function if using `zcash_client_sqlite`).
///
/// Scanned blocks are required to be height-sequential. If a block is missing from the
/// cache, an error will be returned with kind [`ChainInvalid::BlockHeightDiscontinuity`].
@ -235,8 +236,6 @@ where
/// # Ok(())
/// # }
/// ```
///
/// [`init_blocks_table`]: crate::init::init_blocks_table
pub fn scan_cached_blocks<E, N, P, C, D>(
params: &P,
cache: &C,

View File

@ -1,11 +1,11 @@
//! Encoding and decoding functions for Zcash key and address structs.
//!
//! Human-Readable Prefixes (HRPs) for Bech32 encodings are located in the [`zcash_primitives::constants`]
//! module.
//! Human-Readable Prefixes (HRPs) for Bech32 encodings are located in the
//! [zcash_primitives::constants][constants] module.
//!
//! [`constants`]: zcash_primitives::constants
//! [constants]: zcash_primitives::constants
use bech32::{self, Error, FromBase32, ToBase32};
use bech32::{self, Error, FromBase32, ToBase32, Variant};
use bs58::{self, decode::Error as Bs58Error};
use std::convert::TryInto;
use std::io::{self, Write};
@ -21,18 +21,18 @@ where
{
let mut data: Vec<u8> = vec![];
write(&mut data).expect("Should be able to write to a Vec");
bech32::encode(hrp, data.to_base32()).expect("hrp is invalid")
bech32::encode(hrp, data.to_base32(), Variant::Bech32).expect("hrp is invalid")
}
fn bech32_decode<T, F>(hrp: &str, s: &str, read: F) -> Result<Option<T>, Error>
where
F: Fn(Vec<u8>) -> Option<T>,
{
let (decoded_hrp, data) = bech32::decode(s)?;
if decoded_hrp == hrp {
Vec::<u8>::from_base32(&data).map(|data| read(data))
} else {
Ok(None)
match bech32::decode(s)? {
(decoded_hrp, data, Variant::Bech32) if decoded_hrp == hrp => {
Vec::<u8>::from_base32(&data).map(|data| read(data))
}
_ => Ok(None),
}
}
@ -52,11 +52,14 @@ where
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0);
/// let encoded = encode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk);
/// ```
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
pub fn encode_extended_spending_key(hrp: &str, extsk: &ExtendedSpendingKey) -> String {
bech32_encode(hrp, |w| extsk.write(w))
}
/// Decodes an [`ExtendedSpendingKey`] from a Bech32-encoded string.
///
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
pub fn decode_extended_spending_key(
hrp: &str,
s: &str,
@ -82,11 +85,14 @@ pub fn decode_extended_spending_key(
/// let extfvk = ExtendedFullViewingKey::from(&extsk);
/// let encoded = encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &extfvk);
/// ```
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
pub fn encode_extended_full_viewing_key(hrp: &str, extfvk: &ExtendedFullViewingKey) -> String {
bech32_encode(hrp, |w| extfvk.write(w))
}
/// Decodes an [`ExtendedFullViewingKey`] from a Bech32-encoded string.
///
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
pub fn decode_extended_full_viewing_key(
hrp: &str,
s: &str,
@ -127,6 +133,7 @@ pub fn decode_extended_full_viewing_key(
/// "ztestsapling1qqqqqqqqqqqqqqqqqqcguyvaw2vjk4sdyeg0lc970u659lvhqq7t0np6hlup5lusxle75ss7jnk",
/// );
/// ```
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String {
bech32_encode(hrp, |w| w.write_all(&addr.to_bytes()))
}
@ -167,6 +174,7 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String {
/// Ok(Some(pa)),
/// );
/// ```
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
pub fn decode_payment_address(hrp: &str, s: &str) -> Result<Option<PaymentAddress>, Error> {
bech32_decode(hrp, s, |data| {
if data.len() != 43 {
@ -210,6 +218,7 @@ pub fn decode_payment_address(hrp: &str, s: &str) -> Result<Option<PaymentAddres
/// "t26YoyZ1iPgiMEWL4zGUm74eVWfhyDMXzY2",
/// );
/// ```
/// [`TransparentAddress`]: zcash_primitives::legacy::TransparentAddress
pub fn encode_transparent_address(
pubkey_version: &[u8],
script_version: &[u8],
@ -263,6 +272,7 @@ pub fn encode_transparent_address(
/// Ok(Some(TransparentAddress::Script([0; 20]))),
/// );
/// ```
/// [`TransparentAddress`]: zcash_primitives::legacy::TransparentAddress
pub fn decode_transparent_address(
pubkey_version: &[u8],
script_version: &[u8],

View File

@ -17,6 +17,7 @@ use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey};
///
/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0);
/// ```
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendingKey {
if seed.len() < 32 {
panic!("ZIP 32 seeds MUST be at least 32 bytes");

View File

@ -63,6 +63,8 @@ pub struct WalletShieldedOutput<N> {
pub nf: N,
}
/// Information about a note that is tracked by the wallet that is available for spending,
/// with sufficient information for use in note selection.
pub struct SpendableNote {
pub diversifier: Diversifier,
pub note_value: Amount,

View File

@ -23,6 +23,8 @@ use crate::wallet::{AccountId, WalletShieldedOutput, WalletShieldedSpend, Wallet
///
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented
/// with this output's commitment.
///
/// [`ScanningKey`]: crate::welding_rig::ScanningKey
#[allow(clippy::too_many_arguments)]
fn scan_output<P: consensus::Parameters, K: ScanningKey>(
params: &P,
@ -88,10 +90,23 @@ fn scan_output<P: consensus::Parameters, K: ScanningKey>(
/// A key that can be used to perform trial decryption and nullifier
/// computation for a Sapling [`CompactOutput`]
///
/// The purpose of this trait is to enable [`scan_block`]
/// and related methods to be used with either incoming viewing keys
/// or full viewing keys, with the data returned from trial decryption
/// being dependent upon the type of key used. In the case that an
/// incoming viewing key is used, only the note and payment address
/// will be returned; in the case of a full viewing key, the
/// nullifier for the note can also be obtained.
///
/// [`CompactOutput`]: crate::proto::compact_formats::CompactOutput
/// [`scan_block`]: crate::welding_rig::scan_block
pub trait ScanningKey {
/// The type of nullifier extracted when a note is successfully
/// obtained by trial decryption.
type Nf;
/// Attempts to decrypt a Sapling note and payment address
/// from the specified ciphertext using this scanning key.
fn try_decryption<P: consensus::Parameters>(
&self,
params: &P,
@ -101,9 +116,18 @@ pub trait ScanningKey {
ct: &[u8],
) -> Option<(Note, PaymentAddress)>;
/// Produces the nullifier for the specified note and witness, if possible.
///
/// IVK-based implementations of this trait cannot successfully derive
/// nullifiers, in which case `Self::Nf` should be set to the unit type
/// and this function is a no-op.
fn nf(&self, note: &Note, witness: &IncrementalWitness<Node>) -> Self::Nf;
}
/// The [`ScanningKey`] implementation for [`ExtendedFullViewingKey`]s.
/// Nullifiers may be derived when scanning with these keys.
///
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
impl ScanningKey for ExtendedFullViewingKey {
type Nf = Nullifier;
@ -123,6 +147,10 @@ impl ScanningKey for ExtendedFullViewingKey {
}
}
/// The [`ScanningKey`] implementation for [`SaplingIvk`]s.
/// Nullifiers cannot be derived when scanning with these keys.
///
/// [`SaplingIvk`]: zcash_primitives::primitives::SaplingIvk
impl ScanningKey for SaplingIvk {
type Nf = ();
@ -152,16 +180,17 @@ impl ScanningKey for SaplingIvk {
/// The implementation of [`ScanningKey`] may either support or omit the computation of
/// the nullifiers for received notes; the implementation for [`ExtendedFullViewingKey`]
/// will derive the nullifiers for received notes and return them as part of the resulting
/// [`WalletShieldedOutput`]s, whereas since the implementation for [`SaplingIvk`] cannot
/// do so and it will return the unit value in those outputs instead.
/// [`WalletShieldedOutput`]s, whereas the implementation for [`SaplingIvk`] cannot
/// do so and will return the unit value in those outputs instead.
///
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
/// [`SaplingIvk`]: zcash_primitives::SaplingIvk
/// [`SaplingIvk`]: zcash_primitives::primitives::SaplingIvk
/// [`CompactBlock`]: crate::proto::compact_formats::CompactBlock
/// [`ScanningKey`]: self::ScanningKey
/// [`ScanningKey`]: crate::welding_rig::ScanningKey
/// [`CommitmentTree`]: zcash_primitives::merkle_tree::CommitmentTree
/// [`IncrementalWitness`]: zcash_primitives::merkle_tree::IncrementalWitness
/// [`WalletShieldedOutput`]: crate::wallet::WalletShieldedOutput
/// [`WalletTx`]: crate::wallet::WalletTx
pub fn scan_block<P: consensus::Parameters, K: ScanningKey>(
params: &P,
block: CompactBlock,

View File

@ -462,7 +462,7 @@ mod parse {
Ok(payment)
}
/// Parser that consumes the leading "zcash:[address]" from
/// Parser that consumes the leading "zcash:\[address\]" from
/// a ZIP 321 URI.
pub fn lead_addr<'a, P: consensus::Parameters>(
params: &'a P,

View File

@ -29,6 +29,13 @@ same as before, but have been reorganized.
### Removed
- `zcash_client_sqlite::address` module (moved to `zcash_client_backend`).
### Fixed
- Shielded transactions created by the wallet that have no change output (fully
spending their input notes) are now correctly detected as mined when scanning
compact blocks.
- Unshielding transactions created by the wallet (with a transparent recipient
address) that have no change output no longer cause a panic.
## [0.2.1] - 2020-10-24
### Fixed
- `transact::create_to_address` now correctly reconstructs notes from the data

View File

@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
edition = "2018"
[dependencies]
bech32 = "0.7"
bech32 = "0.8"
bs58 = { version = "0.4", features = ["check"] }
ff = "0.8"
group = "0.8"

View File

@ -477,14 +477,13 @@ pub fn get_nullifiers<P>(
wdb: &WalletDB<P>,
) -> Result<Vec<(AccountId, Nullifier)>, SqliteClientError> {
// Get the nullifiers for the notes we are tracking
let mut stmt_fetch_nullifiers = wdb
.conn
.prepare(
"SELECT rn.id_note, rn.account, rn.nf, tx.block as block
let mut stmt_fetch_nullifiers = wdb.conn.prepare(
"SELECT rn.id_note, rn.account, rn.nf, tx.block as block
FROM received_notes rn
LEFT OUTER JOIN transactions tx
ON tx.id_tx = rn.spent
WHERE block IS NULL")?;
WHERE block IS NULL",
)?;
let nullifiers = stmt_fetch_nullifiers.query_map(NO_PARAMS, |row| {
let account = AccountId(row.get(1)?);
let nf_bytes: Vec<u8> = row.get(2)?;

View File

@ -687,7 +687,7 @@ mod tests {
let (cb, _) = fake_compact_block(
sapling_activation_height(),
BlockHash([0; 32]),
extfvk.clone(),
extfvk,
value,
);
insert_into_cache(&db_cache, &cb);

View File

@ -3,7 +3,8 @@
//! `regtest` is a `zcashd`-specific environment used for local testing. They mostly reuse
//! the testnet constants.
//! These constants are defined in [the `zcashd` codebase].
//! [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L482-L496
//!
//! [the `zcashd` codebase]: <https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L482-L496>
/// The regtest cointype reuses the testnet cointype
pub const COIN_TYPE: u32 = 1;
@ -13,7 +14,7 @@ pub const COIN_TYPE: u32 = 1;
/// It is defined in [the `zcashd` codebase].
///
/// [`ExtendedSpendingKey`]: crate::zip32::ExtendedSpendingKey
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L496
/// [the `zcashd` codebase]: <https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L496>
pub const HRP_SAPLING_EXTENDED_SPENDING_KEY: &str = "secret-extended-key-regtest";
/// The HRP for a Bech32-encoded regtest [`ExtendedFullViewingKey`].
@ -21,7 +22,7 @@ pub const HRP_SAPLING_EXTENDED_SPENDING_KEY: &str = "secret-extended-key-regtest
/// It is defined in [the `zcashd` codebase].
///
/// [`ExtendedFullViewingKey`]: crate::zip32::ExtendedFullViewingKey
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L494
/// [the `zcashd` codebase]: <https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L494>
pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewregtestsapling";
/// The HRP for a Bech32-encoded regtest [`PaymentAddress`].
@ -29,7 +30,7 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewregtestsapling";
/// It is defined in [the `zcashd` codebase].
///
/// [`PaymentAddress`]: crate::primitives::PaymentAddress
/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L493
/// [the `zcashd` codebase]: <https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L493>
pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zregtestsapling";
/// The prefix for a Base58Check-encoded regtest [`TransparentAddress::PublicKey`].

View File

@ -9,8 +9,8 @@ use std::str;
/// Format a byte array as a colon-delimited hex string.
///
/// Source: https://github.com/tendermint/signatory
/// License: MIT / Apache 2.0
/// - Source: <https://github.com/tendermint/signatory>
/// - License: MIT / Apache 2.0
fn fmt_colon_delimited_hex<B>(f: &mut fmt::Formatter<'_>, bytes: B) -> fmt::Result
where
B: AsRef<[u8]>,

View File

@ -49,7 +49,7 @@ 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
/// with dummy outputs if necessary. See https://github.com/zcash/zcash/issues/3615
/// with dummy outputs if necessary. See <https://github.com/zcash/zcash/issues/3615>.
const MIN_SHIELDED_OUTPUTS: usize = 2;
#[derive(Debug, PartialEq)]

View File

@ -142,9 +142,9 @@ pub struct TzeIn {
pub witness: tze::Witness,
}
/// Transaction encoding and decoding functions conforming to ZIP-222
/// Transaction encoding and decoding functions conforming to [ZIP 222].
///
/// https://zips.z.cash/zip-0222#encoding-in-transactions
/// [ZIP 222]: https://zips.z.cash/zip-0222#encoding-in-transactions
#[cfg(feature = "zfuture")]
impl TzeIn {
/// Convenience constructor

View File

@ -64,25 +64,16 @@ macro_rules! update_hash {
}
fn has_overwinter_components(version: &TxVersion) -> bool {
match version {
TxVersion::Sprout(_) => false,
_ => true,
}
!matches!(version, TxVersion::Sprout(_))
}
fn has_sapling_components(version: &TxVersion) -> bool {
match version {
TxVersion::Sprout(_) | TxVersion::Overwinter => false,
_ => true,
}
!matches!(version, TxVersion::Sprout(_) | TxVersion::Overwinter)
}
#[cfg(feature = "zfuture")]
fn has_tze_components(version: &TxVersion) -> bool {
match version {
TxVersion::ZFuture => true,
_ => false,
}
matches!(version, TxVersion::ZFuture)
}
fn prevout_hash(vin: &[TxIn]) -> Blake2bHash {