Skip to content

Commit ba99ab5

Browse files
dairanuttycomJack Grigg
committed
ZIP 320 implementation work-in-progress.
Co-authored-by: Kris Nuttycombe <[email protected]> Co-authored-by: Jack Grigg <[email protected]> Signed-off-by: Daira-Emma Hopwood <[email protected]>
1 parent 79f6b02 commit ba99ab5

File tree

17 files changed

+883
-236
lines changed

17 files changed

+883
-236
lines changed

zcash_client_backend/CHANGELOG.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@ and this library adheres to Rust's notion of
66
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
### Notable changes
10+
`zcash_client_backend` now supports TEX (transparent-source-only) addresses as specified
11+
in ZIP 320. Sending to one or more TEX addresses will automatically create a multi-step
12+
proposal that uses two transactions. This is intended to be used in conjunction with
13+
`zcash_client_sqlite` 0.11 or later.
14+
15+
In order to take advantage of this support, client wallets will need to be able to send
16+
multiple transactions created from `zcash_client_backend::data_api::wallet::create_proposed_transactions`.
17+
This API was added in `zcash_client_backend` 0.11.0 but previously could only return a
18+
single transaction.
19+
20+
**Note:** This feature changes the use of transparent addresses in ways that are relevant
21+
to security and access to funds, and that may interact with other wallet behaviour. In
22+
particular it exposes new ephemeral transparent addresses belonging to the wallet, which
23+
need to be scanned in order to recover funds if the first transaction of the proposal is
24+
mined but the second is not, or if someone (e.g. the TEX-address recipient) sends back
25+
funds to those addresses. See [ZIP 320](https://zips.z.cash/zip-0320) for details.
926

1027
### Added
1128
- `zcash_client_backend::data_api`:
@@ -33,7 +50,9 @@ and this library adheres to Rust's notion of
3350
- `zcash_client_backend::input_selection::GreedyInputSelectorError` has a
3451
new variant `UnsupportedTexAddress`.
3552
- `zcash_client_backend::wallet`:
36-
- `Recipient` variants have changed. Instead of wrapping protocol-address
53+
- `Recipient` variants have changed. It has a new `EphemeralTransparent`
54+
variant, and an extra generic parameter giving the type of metadata about
55+
an ephemeral transparent outpoint. Instead of wrapping protocol-address
3756
types, the `External` and `InternalAccount` variants now wrap a
3857
`zcash_address::ZcashAddress`. This simplifies the process of tracking
3958
the original address to which value was sent.

zcash_client_backend/proto/proposal.proto

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ enum FeeRule {
113113
// The proposed change outputs and fee value.
114114
message TransactionBalance {
115115
// A list of change output values.
116+
// Any `ChangeValue`s for the transparent value pool represent ephemeral
117+
// outputs that will each be given a unique t-address.
116118
repeated ChangeValue proposedChange = 1;
117119
// The fee to be paid by the proposed transaction, in zatoshis.
118120
uint64 feeRequired = 2;

zcash_client_backend/src/data_api.rs

+62-11
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,16 @@ use zcash_primitives::{
8888
consensus::BlockHeight,
8989
memo::{Memo, MemoBytes},
9090
transaction::{
91-
components::amount::{BalanceError, NonNegativeAmount},
91+
components::{
92+
amount::{BalanceError, NonNegativeAmount},
93+
OutPoint,
94+
},
9295
Transaction, TxId,
9396
},
9497
};
9598

9699
#[cfg(feature = "transparent-inputs")]
97-
use {
98-
crate::wallet::TransparentAddressMetadata,
99-
zcash_primitives::{legacy::TransparentAddress, transaction::components::OutPoint},
100-
};
100+
use {crate::wallet::TransparentAddressMetadata, zcash_primitives::legacy::TransparentAddress};
101101

102102
#[cfg(any(test, feature = "test-dependencies"))]
103103
use zcash_primitives::consensus::NetworkUpgrade;
@@ -909,6 +909,16 @@ pub trait WalletRead {
909909
) -> Result<HashMap<TransparentAddress, NonNegativeAmount>, Self::Error> {
910910
Ok(HashMap::new())
911911
}
912+
913+
/// Returns the set of reserved ephemeral addresses controlled by this wallet.
914+
#[cfg(feature = "transparent-inputs")]
915+
fn get_reserved_ephemeral_addresses(
916+
&self,
917+
_account: Self::AccountId,
918+
_for_sync: bool,
919+
) -> Result<Vec<TransparentAddress>, Self::Error> {
920+
Ok(vec![])
921+
}
912922
}
913923

914924
/// The relevance of a seed to a given wallet.
@@ -1239,7 +1249,7 @@ impl<'a, AccountId> SentTransaction<'a, AccountId> {
12391249
/// This type is capable of representing both shielded and transparent outputs.
12401250
pub struct SentTransactionOutput<AccountId> {
12411251
output_index: usize,
1242-
recipient: Recipient<AccountId, Note>,
1252+
recipient: Recipient<AccountId, Note, OutPoint>,
12431253
value: NonNegativeAmount,
12441254
memo: Option<MemoBytes>,
12451255
}
@@ -1256,7 +1266,7 @@ impl<AccountId> SentTransactionOutput<AccountId> {
12561266
/// * `memo` - the memo that was sent with this output
12571267
pub fn from_parts(
12581268
output_index: usize,
1259-
recipient: Recipient<AccountId, Note>,
1269+
recipient: Recipient<AccountId, Note, OutPoint>,
12601270
value: NonNegativeAmount,
12611271
memo: Option<MemoBytes>,
12621272
) -> Self {
@@ -1278,8 +1288,8 @@ impl<AccountId> SentTransactionOutput<AccountId> {
12781288
self.output_index
12791289
}
12801290
/// Returns the recipient address of the transaction, or the account id and
1281-
/// resulting note for wallet-internal outputs.
1282-
pub fn recipient(&self) -> &Recipient<AccountId, Note> {
1291+
/// resulting note/outpoint for wallet-internal outputs.
1292+
pub fn recipient(&self) -> &Recipient<AccountId, Note, OutPoint> {
12831293
&self.recipient
12841294
}
12851295
/// Returns the value of the newly created output.
@@ -1514,8 +1524,11 @@ pub trait WalletWrite: WalletRead {
15141524
received_tx: DecryptedTransaction<Self::AccountId>,
15151525
) -> Result<(), Self::Error>;
15161526

1517-
/// Saves information about a transaction that was constructed and sent by the wallet to the
1518-
/// persistent wallet store.
1527+
/// Saves information about a transaction constructed by the wallet to the persistent
1528+
/// wallet store.
1529+
///
1530+
/// The name `store_sent_tx` is somewhat misleading; this must be called *before* the
1531+
/// transaction is sent to the network.
15191532
fn store_sent_tx(
15201533
&mut self,
15211534
sent_tx: &SentTransaction<Self::AccountId>,
@@ -1535,6 +1548,26 @@ pub trait WalletWrite: WalletRead {
15351548
///
15361549
/// There may be restrictions on heights to which it is possible to truncate.
15371550
fn truncate_to_height(&mut self, block_height: BlockHeight) -> Result<(), Self::Error>;
1551+
1552+
/// Reserves the next `n` available ephemeral addresses for the given account.
1553+
/// This cannot be undone, so as far as possible, errors associated with transaction
1554+
/// construction should have been reported before calling this method.
1555+
///
1556+
/// To ensure that sufficient information is stored on-chain to allow recovering
1557+
/// funds sent back to any of the used addresses, a "gap limit" of 20 addresses
1558+
/// should be observed as described in [BIP 44].
1559+
///
1560+
/// Returns an error if there is insufficient space within the gap limit to allocate
1561+
/// the given number of addresses, or if the account identifier does not correspond
1562+
/// to a known account.
1563+
///
1564+
/// [BIP 44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#user-content-Address_gap_limit
1565+
#[cfg(feature = "transparent-inputs")]
1566+
fn reserve_next_n_ephemeral_addresses(
1567+
&mut self,
1568+
account_id: Self::AccountId,
1569+
n: u32,
1570+
) -> Result<Vec<TransparentAddress>, Self::Error>;
15381571
}
15391572

15401573
/// This trait describes a capability for manipulating wallet note commitment trees.
@@ -1862,6 +1895,15 @@ pub mod testing {
18621895
) -> Result<HashMap<TransparentAddress, NonNegativeAmount>, Self::Error> {
18631896
Ok(HashMap::new())
18641897
}
1898+
1899+
#[cfg(feature = "transparent-inputs")]
1900+
fn get_reserved_ephemeral_addresses(
1901+
&self,
1902+
_account: Self::AccountId,
1903+
_for_sync: bool,
1904+
) -> Result<Vec<TransparentAddress>, Self::Error> {
1905+
Ok(vec![])
1906+
}
18651907
}
18661908

18671909
impl WalletWrite for MockWalletDb {
@@ -1924,6 +1966,15 @@ pub mod testing {
19241966
) -> Result<Self::UtxoRef, Self::Error> {
19251967
Ok(0)
19261968
}
1969+
1970+
#[cfg(feature = "transparent-inputs")]
1971+
fn reserve_next_n_ephemeral_addresses(
1972+
&mut self,
1973+
_account_id: Self::AccountId,
1974+
_n: u32,
1975+
) -> Result<Vec<TransparentAddress>, Self::Error> {
1976+
Err(())
1977+
}
19271978
}
19281979

19291980
impl WalletCommitmentTrees for MockWalletDb {

zcash_client_backend/src/data_api/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub enum Error<DataSourceError, CommitmentTreeError, SelectionError, FeeError> {
8585
/// An error occurred parsing the address from a payment request.
8686
Address(ConversionError<&'static str>),
8787

88+
/// The address associated with a record being inserted was not recognized as
89+
/// belonging to the wallet
8890
#[cfg(feature = "transparent-inputs")]
8991
AddressNotRecognized(TransparentAddress),
9092
}

0 commit comments

Comments
 (0)