-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify change strategies, and deprecate or remove fee rules that no longer produce minable transactions #40
Conversation
… instead of a tuple.
…allet metadata. In the process this modifies input selection to take the change strategy as an explicit argument, rather than being wrapped as part of the input selector.
Co-authored-by: Jack Grigg <thestr4d@gmail.com> Co-authored-by: Daira-Emma Hopwood <daira@jacaranda.org>
fixed fees are not standard), and deprecate `fixed::FeeRule::non_standard`. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
…313,Zip313}`. Rename `zcash_client_backend::proto::ProposalDecodingError::FeeRuleNotSpecified` to `FeeRuleNotSupported` and use it to report attempted use of the removed rules. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
that is generic in the fee rule. This should simplify future generalizations of the change strategy. We also undo the changes to `{fixed,standard,zip317}::SingleOutputChangeStrategy` in this commit, and deprecate those types' `new` constructors. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
/// A change strategy that attempts to split the change value into some number of equal-sized notes | ||
/// as dictated by the included [`SplitPolicy`] value. | ||
pub struct MultiOutputChangeStrategy<I> { | ||
fee_rule: Zip317FeeRule, | ||
change_memo: Option<MemoBytes>, | ||
fallback_change_pool: ShieldedProtocol, | ||
dust_output_policy: DustOutputPolicy, | ||
split_policy: SplitPolicy, | ||
meta_source: PhantomData<I>, | ||
} | ||
|
||
impl<I> MultiOutputChangeStrategy<I> { | ||
/// Constructs a new [`MultiOutputChangeStrategy`] with the specified ZIP 317 | ||
/// fee parameters, change memo, and change splitting policy. | ||
/// | ||
/// This change strategy will fall back to creating a single change output if insufficient | ||
/// change value is available to create notes with at least the minimum value dictated by the | ||
/// split policy. | ||
/// | ||
/// - `fallback_change_pool`: the pool to which change will be sent if when more than one | ||
/// shielded pool is enabled via feature flags, and the transaction has no shielded inputs. | ||
/// - `split_policy`: A policy value describing how the change value should be returned as | ||
/// multiple notes. | ||
pub fn new( | ||
fee_rule: Zip317FeeRule, | ||
change_memo: Option<MemoBytes>, | ||
fallback_change_pool: ShieldedProtocol, | ||
dust_output_policy: DustOutputPolicy, | ||
split_policy: SplitPolicy, | ||
) -> Self { | ||
Self { | ||
fee_rule, | ||
change_memo, | ||
fallback_change_pool, | ||
dust_output_policy, | ||
split_policy, | ||
meta_source: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
impl<I: InputSource> ChangeStrategy for MultiOutputChangeStrategy<I> { | ||
type FeeRule = Zip317FeeRule; | ||
type Error = Zip317FeeError; | ||
type MetaSource = I; | ||
type WalletMeta = WalletMeta; | ||
|
||
fn fee_rule(&self) -> &Self::FeeRule { | ||
&self.fee_rule | ||
} | ||
|
||
fn fetch_wallet_meta( | ||
&self, | ||
meta_source: &Self::MetaSource, | ||
account: <Self::MetaSource as InputSource>::AccountId, | ||
exclude: &[<Self::MetaSource as InputSource>::NoteRef], | ||
) -> Result<Self::WalletMeta, <Self::MetaSource as InputSource>::Error> { | ||
meta_source.get_wallet_metadata(account, self.split_policy.min_split_output_size(), exclude) | ||
} | ||
|
||
fn compute_balance<P: consensus::Parameters, NoteRefT: Clone>( | ||
&self, | ||
params: &P, | ||
target_height: BlockHeight, | ||
transparent_inputs: &[impl transparent::InputView], | ||
transparent_outputs: &[impl transparent::OutputView], | ||
sapling: &impl sapling_fees::BundleView<NoteRefT>, | ||
#[cfg(feature = "orchard")] orchard: &impl orchard_fees::BundleView<NoteRefT>, | ||
ephemeral_balance: Option<&EphemeralBalance>, | ||
wallet_meta: Option<&Self::WalletMeta>, | ||
) -> Result<TransactionBalance, ChangeError<Self::Error, NoteRefT>> { | ||
let cfg = SinglePoolBalanceConfig::new( | ||
params, | ||
&self.fee_rule, | ||
&self.dust_output_policy, | ||
self.fee_rule.marginal_fee(), | ||
&self.split_policy, | ||
self.fallback_change_pool, | ||
self.fee_rule.marginal_fee(), | ||
self.fee_rule.grace_actions(), | ||
); | ||
|
||
single_pool_output_balance( | ||
cfg, | ||
wallet_meta, | ||
target_height, | ||
transparent_inputs, | ||
transparent_outputs, | ||
sapling, | ||
#[cfg(feature = "orchard")] | ||
orchard, | ||
self.change_memo.as_ref(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all moved to CommonChangeStrategy
. I intentionally used the most non-committal name possible so that we don't have to change it when we (inevitably) generalize again.
params, | ||
&self.fee_rule, | ||
&self.dust_output_policy, | ||
self.fee_rule.default_dust_threshold(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we have to distinguish default_dust_threshold()
from marginal_fee()
in order to replicate the behaviour of the current fixed fee rule. (There was one test, fees::fixed::tests::dust_change
, that failed if we didn't do that.)
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## wallet/multi_output_change_strategy #40 +/- ##
======================================================================
Coverage ? 62.04%
======================================================================
Files ? 149
Lines ? 19254
Branches ? 0
======================================================================
Hits ? 11947
Misses ? 7307
Partials ? 0 ☔ View full report in Codecov by Sentry. |
@@ -60,6 +50,18 @@ impl super::FeeRule for FeeRule { | |||
) -> Result<NonNegativeAmount, Self::Error> { | |||
Ok(self.fixed_fee) | |||
} | |||
|
|||
fn default_dust_threshold(&self) -> NonNegativeAmount { | |||
self.fixed_fee |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is slightly weird but it is what the previous code did.
@@ -83,7 +83,7 @@ impl FeeRule { | |||
|| p2pkh_standard_input_size > P2PKH_STANDARD_INPUT_SIZE \ | |||
|| p2pkh_standard_output_size > P2PKH_STANDARD_OUTPUT_SIZE` \ | |||
violates ZIP 317, and might cause transactions built with it to fail. \ | |||
This API is likely to be removed. Use `[FeeRule::standard]` instead." | |||
This API is likely to be removed. Use [`FeeRule::standard`] instead." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm itching to remove this one as well. Pretty please?
@@ -13,8 +13,10 @@ and this library adheres to Rust's notion of | |||
- `WalletSummary::progress` | |||
- `WalletMeta` | |||
- `impl Default for wallet::input_selection::GreedyInputSelector` | |||
- `zcash_client_backend::fees::SplitPolicy` | |||
- `zcash_client_backend::fees::zip317::MultiOutputChangeStrategy` | |||
- `zcash_client_backend::fees::{SplitPolicy, CommonChangeStrategy}`. These |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of CommonChangeStrategy
, we should probably call this SinglePoolChangeStrategy
as the distinguishing feature is now that it sends change to a single pool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK on the consolidation, but I have a number of complaint about the type changes being introduced; specifically, DummyMetaSource
.
Also the Common
and simple
names are not helpful.
@@ -907,7 +907,7 @@ pub trait InputSource { | |||
account: Self::AccountId, | |||
min_value: NonNegativeAmount, | |||
exclude: &[Self::NoteRef], | |||
) -> Result<WalletMeta, Self::Error>; | |||
) -> Result<Option<WalletMeta>, Self::Error>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this change semantically - I guess Ok(None)
means that wallet metadata cannot be determined?
let change_memo = "Test change memo".parse::<Memo>().unwrap(); | ||
let change_strategy = standard::SingleOutputChangeStrategy::new( | ||
fee_rule, | ||
let change_strategy = CommonChangeStrategy::simple( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I don't like simple
as a name for a constructor; it doesn't give me any information about what it actually does.
@@ -506,6 +488,43 @@ pub trait ChangeStrategy { | |||
) -> Result<TransactionBalance, ChangeError<Self::Error, NoteRefT>>; | |||
} | |||
|
|||
pub struct DummyMetaSource; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I very much dislike this being part of the public API.
}; | ||
|
||
#[cfg(feature = "orchard")] | ||
use super::orchard as orchard_fees; | ||
|
||
/// A change strategy that attempts to split the change value into some number of equal-sized notes | ||
/// as dictated by the included [`SplitPolicy`] value. | ||
pub struct CommonChangeStrategy<I, FR> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct CommonChangeStrategy<I, FR> { | |
pub struct SinglePoolChangeStrategy<I, FR> { |
And related changes elsewhere
/// and a single change output. This is equivalent to [`CommonChangeStrategy::new`] with | ||
/// `dust_output_policy == DustOutputPolicy::default()` and | ||
/// `split_policy == SplitPolicy::single_output()`. | ||
pub fn simple( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn simple( | |
pub fn single_output( |
and affected call sites
|
||
impl<I: InputSource, FR: FeeRule + Clone> ChangeStrategy for CommonChangeStrategy<I, FR> { | ||
type FeeRule = FR; | ||
type Error = FR::FeeRuleOrBalanceError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look like something that should be an associated type; it should not be necessary to modify zcash_primitives
to introduce this change. Instead, have an enum that wraps the fee rule error.
impl InputSource for DummyMetaSource { | ||
type Error = (); | ||
type AccountId = (); | ||
type NoteRef = (); | ||
|
||
fn get_spendable_note( | ||
&self, | ||
_txid: &TxId, | ||
_protocol: ShieldedProtocol, | ||
_index: u32, | ||
) -> Result<Option<ReceivedNote<Self::NoteRef, Note>>, Self::Error> { | ||
Err(()) | ||
} | ||
|
||
fn select_spendable_notes( | ||
&self, | ||
_account: Self::AccountId, | ||
_target_value: NonNegativeAmount, | ||
_sources: &[ShieldedProtocol], | ||
_anchor_height: BlockHeight, | ||
_exclude: &[Self::NoteRef], | ||
) -> Result<SpendableNotes<Self::NoteRef>, Self::Error> { | ||
Err(()) | ||
} | ||
|
||
fn get_wallet_metadata( | ||
&self, | ||
_account: Self::AccountId, | ||
_min_value: NonNegativeAmount, | ||
_exclude: &[Self::NoteRef], | ||
) -> Result<Option<WalletMeta>, Self::Error> { | ||
Err(()) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NACK on this introduction; a InputSource
type that errors on every call is the wrong way here. The PhantomData
solution was fine.
|
||
/// Returns the default dust threshold. | ||
fn default_dust_threshold(&self) -> NonNegativeAmount; | ||
|
||
/// Returns the marginal fee, i.e. the amount by which the fee increases for each | ||
/// logical action as defined in ZIP 317. | ||
fn marginal_fee(&self) -> NonNegativeAmount; | ||
|
||
/// Returns the number of grace actions, or 0 if this rule does not use grace actions. | ||
fn grace_actions(&self) -> usize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NACK, these are all ZIP 317 specific.
Zip317, | ||
} | ||
|
||
impl FeeRule for StandardFeeRule { | ||
type Error = zip317::FeeError; | ||
type FeeRuleOrBalanceError = zip317::FeeError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NACK on this change; this error type is unused in the zcash_primitives
crate and doesn't justify its existence.
/// Returns the ZIP 317 marginal fee. | ||
pub fn marginal_fee(&self) -> NonNegativeAmount { | ||
self.marginal_fee | ||
} | ||
/// Returns the ZIP 317 number of grace actions | ||
pub fn grace_actions(&self) -> usize { | ||
self.grace_actions | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are intentionally here, instead of in the general trait, because they're concepts specific to ZIP 317.
In general, the way that I would approach this change instead is to deprecate/delete
|
4059a29
to
47b1065
Compare
fixed::FeeRule::standard
(which was misleadingly named because fixed fees are not standard).fixed::FeeRule::non_standard
.zcash_primitives::transaction::fees::StandardFeeRule::{PreZip313,Zip313}
.zcash_client_backend::proto::ProposalDecodingError::FeeRuleNotSpecified
toFeeRuleNotSupported
and use it to report attempted use of the removed rules.CommonChangeStrategy
that is generic in the fee rule. This should simplify future generalizations of the change strategy.{fixed,standard,zip317}::SingleOutputChangeStrategy
, and deprecate those types'new
constructors. They are now implemented as trivial wrappers overCommonChangeStrategy
.