Merge pull request #6242 from sellout/transaction-strategy

Add operations to TransactionStrategy
This commit is contained in:
Kris Nuttycombe 2022-12-12 09:22:25 -07:00 committed by GitHub
commit 4bc92bf7cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 139 additions and 66 deletions

View File

@ -7715,23 +7715,82 @@ std::optional<libzcash::UnifiedAddress> UnifiedAddressForReceiver::operator()(co
return std::nullopt;
}
PrivacyPolicy PrivacyPolicyMeet(PrivacyPolicy a, PrivacyPolicy b)
{
switch (a) {
case PrivacyPolicy::FullPrivacy:
return b;
case PrivacyPolicy::AllowRevealedAmounts:
switch (b) {
case PrivacyPolicy::FullPrivacy:
return a;
default: return b;
};
case PrivacyPolicy::AllowRevealedRecipients:
switch (b) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
return a;
case PrivacyPolicy::AllowRevealedSenders:
return PrivacyPolicy::AllowFullyTransparent;
case PrivacyPolicy::AllowLinkingAccountAddresses:
return PrivacyPolicy::NoPrivacy;
default: return b;
};
case PrivacyPolicy::AllowRevealedSenders:
switch (b) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
return a;
case PrivacyPolicy::AllowRevealedRecipients:
return PrivacyPolicy::AllowFullyTransparent;
default: return b;
};
case PrivacyPolicy::AllowFullyTransparent:
switch (b) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowRevealedSenders:
return a;
case PrivacyPolicy::AllowLinkingAccountAddresses:
return PrivacyPolicy::NoPrivacy;
default: return b;
};
case PrivacyPolicy::AllowLinkingAccountAddresses:
switch (b) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedSenders:
return a;
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowFullyTransparent:
return PrivacyPolicy::NoPrivacy;
default: return b;
};
case PrivacyPolicy::NoPrivacy:
return a;
default: assert(false);
}
}
std::optional<TransactionStrategy> TransactionStrategy::FromString(std::string privacyPolicy) {
TransactionStrategy strategy;
if (privacyPolicy == "FullPrivacy") {
strategy.privacy = PrivacyPolicy::FullPrivacy;
strategy.requestedLevel = PrivacyPolicy::FullPrivacy;
} else if (privacyPolicy == "AllowRevealedAmounts") {
strategy.privacy = PrivacyPolicy::AllowRevealedAmounts;
strategy.requestedLevel = PrivacyPolicy::AllowRevealedAmounts;
} else if (privacyPolicy == "AllowRevealedRecipients") {
strategy.privacy = PrivacyPolicy::AllowRevealedRecipients;
strategy.requestedLevel = PrivacyPolicy::AllowRevealedRecipients;
} else if (privacyPolicy == "AllowRevealedSenders") {
strategy.privacy = PrivacyPolicy::AllowRevealedSenders;
strategy.requestedLevel = PrivacyPolicy::AllowRevealedSenders;
} else if (privacyPolicy == "AllowFullyTransparent") {
strategy.privacy = PrivacyPolicy::AllowFullyTransparent;
strategy.requestedLevel = PrivacyPolicy::AllowFullyTransparent;
} else if (privacyPolicy == "AllowLinkingAccountAddresses") {
strategy.privacy = PrivacyPolicy::AllowLinkingAccountAddresses;
strategy.requestedLevel = PrivacyPolicy::AllowLinkingAccountAddresses;
} else if (privacyPolicy == "NoPrivacy") {
strategy.privacy = PrivacyPolicy::NoPrivacy;
strategy.requestedLevel = PrivacyPolicy::NoPrivacy;
} else {
// Unknown privacy policy.
return std::nullopt;
@ -7740,72 +7799,49 @@ std::optional<TransactionStrategy> TransactionStrategy::FromString(std::string p
return strategy;
}
bool TransactionStrategy::AllowRevealedAmounts() {
switch (privacy) {
std::string TransactionStrategy::ToString(PrivacyPolicy policy) {
switch (policy) {
case PrivacyPolicy::FullPrivacy:
return false;
return "FullPrivacy";
case PrivacyPolicy::AllowRevealedAmounts:
return "AllowRevealedAmounts";
case PrivacyPolicy::AllowRevealedRecipients:
return "AllowRevealedRecipients";
case PrivacyPolicy::AllowRevealedSenders:
return "AllowRevealedSenders";
case PrivacyPolicy::AllowFullyTransparent:
return "AllowFullyTransparent";
case PrivacyPolicy::AllowLinkingAccountAddresses:
return "AllowLinkingAccountAddresses";
case PrivacyPolicy::NoPrivacy:
return true;
return "NoPrivacy";
default:
// Fail closed.
return false;
assert(false);
}
}
bool TransactionStrategy::AllowRevealedRecipients() {
switch (privacy) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowLinkingAccountAddresses:
return false;
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowFullyTransparent:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.
return false;
}
bool TransactionStrategy::AllowRevealedAmounts() const {
return IsCompatibleWith(PrivacyPolicy::AllowRevealedAmounts);
}
bool TransactionStrategy::AllowRevealedSenders() {
switch (privacy) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients:
return false;
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowFullyTransparent:
case PrivacyPolicy::AllowLinkingAccountAddresses:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.
return false;
}
bool TransactionStrategy::AllowRevealedRecipients() const {
return IsCompatibleWith(PrivacyPolicy::AllowRevealedRecipients);
}
bool TransactionStrategy::AllowLinkingAccountAddresses() {
switch (privacy) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowFullyTransparent:
return false;
case PrivacyPolicy::AllowLinkingAccountAddresses:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.
return false;
}
bool TransactionStrategy::AllowRevealedSenders() const {
return IsCompatibleWith(PrivacyPolicy::AllowRevealedSenders);
}
bool TransactionStrategy::AllowFullyTransparent() const {
return IsCompatibleWith(PrivacyPolicy::AllowFullyTransparent);
}
bool TransactionStrategy::AllowLinkingAccountAddresses() const {
return IsCompatibleWith(PrivacyPolicy::AllowLinkingAccountAddresses);
}
bool TransactionStrategy::IsCompatibleWith(PrivacyPolicy policy) const {
return requestedLevel == PrivacyPolicyMeet(requestedLevel, policy);
}
bool ZTXOSelector::SelectsTransparent() const {

View File

@ -759,6 +759,9 @@ public:
/**
* A strategy to use for managing privacy when constructing a transaction.
*
* **NB**: These are intentionally in an order where `<` will never do the right
* thing. See `PrivacyPolicyMeet` for a correct comparison.
*/
enum class PrivacyPolicy {
FullPrivacy,
@ -770,20 +773,54 @@ enum class PrivacyPolicy {
NoPrivacy,
};
/**
* Privacy policies form a lattice where the relation is strictness. I.e.,
* `x y` means Policy `x` allows at least everything that policy `y` allows.
*
* This function returns the meet (greatest lower bound) of `a` and `b`, i.e.
* the strictest policy that allows everything allowed by `a` and also
* everything allowed by `b`.
*
* See #6240 for the graph that this models.
*/
PrivacyPolicy PrivacyPolicyMeet(PrivacyPolicy a, PrivacyPolicy b);
class TransactionStrategy {
PrivacyPolicy privacy;
PrivacyPolicy requestedLevel;
public:
TransactionStrategy() : privacy(PrivacyPolicy::FullPrivacy) {}
TransactionStrategy(const TransactionStrategy& strategy) : privacy(strategy.privacy) {}
TransactionStrategy(PrivacyPolicy privacyPolicy) : privacy(privacyPolicy) {}
TransactionStrategy() : requestedLevel(PrivacyPolicy::FullPrivacy) {}
TransactionStrategy(const TransactionStrategy& strategy) : requestedLevel(strategy.requestedLevel) {}
TransactionStrategy(PrivacyPolicy privacyPolicy) : requestedLevel(privacyPolicy) {}
static std::optional<TransactionStrategy> FromString(std::string privacyPolicy);
static std::string ToString(PrivacyPolicy policy);
bool AllowRevealedAmounts();
bool AllowRevealedRecipients();
bool AllowRevealedSenders();
bool AllowLinkingAccountAddresses();
std::string PolicyName() const {
return ToString(requestedLevel);
}
bool AllowRevealedAmounts() const;
bool AllowRevealedRecipients() const;
bool AllowRevealedSenders() const;
bool AllowFullyTransparent() const;
bool AllowLinkingAccountAddresses() const;
/**
* This strategy is compatible with a given policy if it is identical to or
* less strict than the policy.
*
* For example, if a transaction requires a policy no stricter than
* `AllowRevealedSenders`, then that transaction can safely be constructed
* if the user specifies `AllowLinkingAccountAddresses`, because
* `AllowLinkingAccountAddresses` is compatible with `AllowRevealedSenders`
* (the transaction will not link addresses anyway). However, if the
* transaction required `AllowRevealedRecipients`, it could not be
* constructed, because `AllowLinkingAccountAddresses` is _not_ compatible
* with `AllowRevealedRecipients` (the transaction reveals recipients, which
* is not allowed by `AllowLinkingAccountAddresses`.
*/
bool IsCompatibleWith(PrivacyPolicy policy) const;
};
/**