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; 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) { std::optional<TransactionStrategy> TransactionStrategy::FromString(std::string privacyPolicy) {
TransactionStrategy strategy; TransactionStrategy strategy;
if (privacyPolicy == "FullPrivacy") { if (privacyPolicy == "FullPrivacy") {
strategy.privacy = PrivacyPolicy::FullPrivacy; strategy.requestedLevel = PrivacyPolicy::FullPrivacy;
} else if (privacyPolicy == "AllowRevealedAmounts") { } else if (privacyPolicy == "AllowRevealedAmounts") {
strategy.privacy = PrivacyPolicy::AllowRevealedAmounts; strategy.requestedLevel = PrivacyPolicy::AllowRevealedAmounts;
} else if (privacyPolicy == "AllowRevealedRecipients") { } else if (privacyPolicy == "AllowRevealedRecipients") {
strategy.privacy = PrivacyPolicy::AllowRevealedRecipients; strategy.requestedLevel = PrivacyPolicy::AllowRevealedRecipients;
} else if (privacyPolicy == "AllowRevealedSenders") { } else if (privacyPolicy == "AllowRevealedSenders") {
strategy.privacy = PrivacyPolicy::AllowRevealedSenders; strategy.requestedLevel = PrivacyPolicy::AllowRevealedSenders;
} else if (privacyPolicy == "AllowFullyTransparent") { } else if (privacyPolicy == "AllowFullyTransparent") {
strategy.privacy = PrivacyPolicy::AllowFullyTransparent; strategy.requestedLevel = PrivacyPolicy::AllowFullyTransparent;
} else if (privacyPolicy == "AllowLinkingAccountAddresses") { } else if (privacyPolicy == "AllowLinkingAccountAddresses") {
strategy.privacy = PrivacyPolicy::AllowLinkingAccountAddresses; strategy.requestedLevel = PrivacyPolicy::AllowLinkingAccountAddresses;
} else if (privacyPolicy == "NoPrivacy") { } else if (privacyPolicy == "NoPrivacy") {
strategy.privacy = PrivacyPolicy::NoPrivacy; strategy.requestedLevel = PrivacyPolicy::NoPrivacy;
} else { } else {
// Unknown privacy policy. // Unknown privacy policy.
return std::nullopt; return std::nullopt;
@ -7740,72 +7799,49 @@ std::optional<TransactionStrategy> TransactionStrategy::FromString(std::string p
return strategy; return strategy;
} }
bool TransactionStrategy::AllowRevealedAmounts() { std::string TransactionStrategy::ToString(PrivacyPolicy policy) {
switch (privacy) { switch (policy) {
case PrivacyPolicy::FullPrivacy: case PrivacyPolicy::FullPrivacy:
return false; return "FullPrivacy";
case PrivacyPolicy::AllowRevealedAmounts: case PrivacyPolicy::AllowRevealedAmounts:
return "AllowRevealedAmounts";
case PrivacyPolicy::AllowRevealedRecipients: case PrivacyPolicy::AllowRevealedRecipients:
return "AllowRevealedRecipients";
case PrivacyPolicy::AllowRevealedSenders: case PrivacyPolicy::AllowRevealedSenders:
return "AllowRevealedSenders";
case PrivacyPolicy::AllowFullyTransparent: case PrivacyPolicy::AllowFullyTransparent:
return "AllowFullyTransparent";
case PrivacyPolicy::AllowLinkingAccountAddresses: case PrivacyPolicy::AllowLinkingAccountAddresses:
return "AllowLinkingAccountAddresses";
case PrivacyPolicy::NoPrivacy: case PrivacyPolicy::NoPrivacy:
return true; return "NoPrivacy";
default: default:
// Fail closed. assert(false);
return false;
} }
} }
bool TransactionStrategy::AllowRevealedRecipients() { bool TransactionStrategy::AllowRevealedAmounts() const {
switch (privacy) { return IsCompatibleWith(PrivacyPolicy::AllowRevealedAmounts);
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::AllowRevealedSenders() { bool TransactionStrategy::AllowRevealedRecipients() const {
switch (privacy) { return IsCompatibleWith(PrivacyPolicy::AllowRevealedRecipients);
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::AllowLinkingAccountAddresses() { bool TransactionStrategy::AllowRevealedSenders() const {
switch (privacy) { return IsCompatibleWith(PrivacyPolicy::AllowRevealedSenders);
case PrivacyPolicy::FullPrivacy: }
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients: bool TransactionStrategy::AllowFullyTransparent() const {
case PrivacyPolicy::AllowRevealedSenders: return IsCompatibleWith(PrivacyPolicy::AllowFullyTransparent);
case PrivacyPolicy::AllowFullyTransparent: }
return false;
case PrivacyPolicy::AllowLinkingAccountAddresses: bool TransactionStrategy::AllowLinkingAccountAddresses() const {
case PrivacyPolicy::NoPrivacy: return IsCompatibleWith(PrivacyPolicy::AllowLinkingAccountAddresses);
return true; }
default:
// Fail closed. bool TransactionStrategy::IsCompatibleWith(PrivacyPolicy policy) const {
return false; return requestedLevel == PrivacyPolicyMeet(requestedLevel, policy);
}
} }
bool ZTXOSelector::SelectsTransparent() const { bool ZTXOSelector::SelectsTransparent() const {

View File

@ -759,6 +759,9 @@ public:
/** /**
* A strategy to use for managing privacy when constructing a transaction. * 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 { enum class PrivacyPolicy {
FullPrivacy, FullPrivacy,
@ -770,20 +773,54 @@ enum class PrivacyPolicy {
NoPrivacy, 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 { class TransactionStrategy {
PrivacyPolicy privacy; PrivacyPolicy requestedLevel;
public: public:
TransactionStrategy() : privacy(PrivacyPolicy::FullPrivacy) {} TransactionStrategy() : requestedLevel(PrivacyPolicy::FullPrivacy) {}
TransactionStrategy(const TransactionStrategy& strategy) : privacy(strategy.privacy) {} TransactionStrategy(const TransactionStrategy& strategy) : requestedLevel(strategy.requestedLevel) {}
TransactionStrategy(PrivacyPolicy privacyPolicy) : privacy(privacyPolicy) {} TransactionStrategy(PrivacyPolicy privacyPolicy) : requestedLevel(privacyPolicy) {}
static std::optional<TransactionStrategy> FromString(std::string privacyPolicy); static std::optional<TransactionStrategy> FromString(std::string privacyPolicy);
static std::string ToString(PrivacyPolicy policy);
bool AllowRevealedAmounts(); std::string PolicyName() const {
bool AllowRevealedRecipients(); return ToString(requestedLevel);
bool AllowRevealedSenders(); }
bool AllowLinkingAccountAddresses();
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;
}; };
/** /**