Hey everyone,
There have been many requests for support in the Stellar protocol to pay the reserve for ledger entries from another account. Based on these requests, I have drafted https://github.com/stellar/stellar-protocol/blob/master/core/cap-0031.md which introduces a generic mechanism for this. To show what is possible, this proposal contains more than what I think would actually be included in the first version of an implementation. I am unsure, for example, about including offer sponsorship due to its complexity unless people see that it would be extremely valuable.
The proposal looks very long, but most of it is just a detailed explanation of required changes to operations in order to do the new book-keeping.
I would appreciate any and all feedback. Love it? Hate it? Does/doesn’t meet your requirements? Do/don’t like the approach? Let me know.
Thanks,
Jon
## Xdr
### AccountEntry
Should extend `v1()` instead of creating `v2()` see https://github.com/stellar/stellar-core/blob/master/docs/versioning.md#ledger-object-versioning
### CreateSponsorshipResult
Should probably return the sponsorship ID? Otherwise, how does the caller know the mapping?
### Missing LedgerHeader changes?
You're using a global `sponsorshipID` generator that probably needs to be tracked in the ledger header; that or there needs to be a way to generate those IDs.
## Semantics
There should be an intro paragraph that in addition to the explanation on how we calculate the available balance, explains how sponsorship actually works: right now the reader has to go over each operation and figure it out.
In particular, this intro should allow to also implement invariants.
From what I understand:
* creating sponsorships always succeeds (if the account has enough balance)
* `sponsoredReserves` tracks currently sponsored entries, ie we always have `2 + numSubEntries - sponsoredReserves >= 0` (ie, we don't count redundant sponsors against `sponsoredReserves`).
* corollary: when creating/removing ledger entries, we have to keep `sponsoredReserves` up to date
* only one thing sponsored by sponsored entry
There are no mentions of how certain things work (and why), in particular:
* is there a limit on the number of sponsors?
* related, the constant use of `count sponsorships` seems to indicate to me that we need to store this information somewhere - so why not just add a LedgerEntry for this?
* sponsorships should probably counted as subentries for the sponsor account, otherwise the account can be merged and this creates a bunch of new problems.
* sponsorships cannot be deleted if "in use" - why?
* a sponsor may only want to sponsor accounts "in good standing" (ie, they're actually using the trustline)
* this is especially problematic as there is no 1:1 mapping between what is being sponsored and sponsor, so a sponsor may get stuck to sponsor an account that deleted what they were sponsoring.
* should there be a way for accounts to disable sponsorships? As this changes the "available balance" of an account, this may cause operational problems to automated systems, in particular it may change the behavior of many operations, especially as the sponsor can remove its sponsorship at any time which causes the available balance to go down.
* ~ related, why not allow the sponsored account to remove sponsorships attached to their account?
* behavior wrt base reserve increase
* when a sponsorship becomes "used", there is no check that compares the current base reserve to the one stored in the sponsorship entry - this can be problematic as it creates a (potentially large) incentive to create (potentially a lot) sponsorship entries ahead of a base reserve increase.
* Any reason to not make references to assets in Trustline, offers optional as to match on anything? (this probably depends on relaxing the "in use" rule)
* sponsoring of specific "Data" field doesn't seem super useful and is wasteful? Maybe first version should not have this (or make optional too?)
* why not allow more than 1 sponsorship per entry? Signers, Data(?), Offers could benefit from a counter.
## Operations
General readability: when writing pseudo code, it would be easier to read if you were writing things in a more "standard way", right now you're using something that is a cross between Fortran (gotos everywhere) and Perl/Ruby (postfix conditions). I would use python-like pseudo code instead that makes great use of indentation, can include comments to label sections, and doesn't use "goto", for example:
```
# ensure that `sourceAccount` can pay for this
if the `sourceAccount` does not have at least `Multiplier * baseReserve` available balance of native asset:
Fail with `CREATE_SPONSORSHIP_LOW_RESERVE`
```
### Creation
I don't think we should allow an account to sponsor themselves, it looks like you allow it.
You didn't specify when and how `sponsorshipID` gets generated (it seems it's just incremented).
Step 4: I wonder if we should just store `sponsorship.reserve = baseReserve` to avoid having to divide by the multiplier everywhere we use sponsorships.
Step 5 says "number of LedgerEntry" but that doesn't seem right, for signers, this number would be 1 but we want to sponsor based on the number of signers. So should be "number of subentries".
Also, for other types (like `OfferEntry`), this seems to be very inefficient.
Step 6, I don't understand why there is the condition on `sponsorshipID`. How can this condition be false as we're creating a new entry?
Also, how can this be done efficiently (maybe tracking this in a separate ledger entry solves this problem)?
Step 8..11 should have a comment that explains that we're sponsoring an existing entry.
### Other operations
I didn't review other operations in detail as there was already too many question on "Create", so here are only some questions.
#### removeSponsorshipOp
I don't see why we need the complexity from step 5 & 6:
* 5 makes it impossible to transfer
sponsorship
* 6 makes it impossible to stop sponsoring something
I imagine that you're trying to preserve some mapping between groups (as described at the end of "How are sponsorship entries paired with the ledger entries they sponsor"); but this is not super useful as we don't even have the right properties even for a single sponsor:
If a sponsored account has 2 signers sponsored, it can easily create 2 new signers, and delete the ones that the sponsor wanted to sponsor.
So I would make all sponsors (for a given condition) fungible instead, that way you only need the count for that condition without a constraint on IDs.
## Semantics for offers
I don't think we should allow sponsoring of all types from the get go, in particular offers.
Having "sponsored offers" has no alignment with "cross border payment" and comes with overhead at basically every stage (ie it's not a "freebie"):
* offers get taken all the time, so this adds a lot of churn to the ledger.
#### CreateAccount
This applies to other existing operations.
I don't understand what "step 1" is referencing - maybe you're just trying to say we're replacing "this" with "that", but in that case, just write down what is being replaced.
For create account, it seems that we also need to set `sponsoredReserves` to `2` when we're creating a sponsored account?
#### Merge account
Merge needs to be modified so that we have the proper behavior if the account is sponsored and/or has sponsored signers.
--
You received this message because you are subscribed to the Google Groups "Stellar Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAG4FKhycnUsUHcyjUg-5N4tDhvRMGeXWTgQAyxENjppruTnRJQ%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "Stellar Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/e9707d27-e833-4011-bc2b-1bf585b570c7%40googlegroups.com.
Looks like you responded to Leigh's thread by accident
(From the "Semantics" section)
> > sponsorships should probably counted as subentries for the sponsor account, otherwise the account can be merged and this creates a bunch of new problems.
> It is actually the opposite: counting sponsorships as subentries creates problems for MergeOp. Specifically, there is no guarantee that you can ever get a sponsorship back (see "6 makes it impossible to stop sponsoring something" item 1). This means that if sponsorships are subentries, then it may be impossible to merge your account. You noted at the end of your comments that "Merge needs to be modified so that we have the proper behavior if the account is sponsored and/or has sponsored signers." Actually, everything just works correctly as is. Merging should move the entire balance from the source account into the destination account, but should not interact with the sponsorship entries because the point of sponsorship is that it does not allow the sponsored reserve to move. The destination account of a merge does not undergo any change in its subentries (eg. the signers do not merge) so it also does not interact with its sponsorships. Aside from all of this, making sponsorships not be subentries allows for an unlimited number of them. Remarks like this already exist in CAP-0023 and CAP-0032, and I will add them to CAP-0031.
I guess we can resolve this question later as it depends on overall behavior. I agree that with the proposal as written sponsorships are completely detached from accounts.
> > why not allow the sponsored account to remove sponsorships attached to their account?
> A sponsorship is free money, since they cannot be removed when in use according to this proposal. As a consequence, there is no reason to ever remove them.
This was a sub-question to the question "should there be a way for accounts to disable sponsorships?", without which it may cause unnecessary pain for accounts that don't expect to be sponsored (exchange accounts for example).
> > when a sponsorship becomes "used", there is no check that compares the current base reserve to the one stored in the sponsorship entry - this can be problematic as it creates a (potentially large) incentive to create (potentially a lot) sponsorship entries ahead of a base reserve increase.
> This is a really good point, but I don't know exactly what to do about it yet. The challenge is that we don't modify the sponsorship entries when they come into use, so there is no way to know if it had the right reserve at that time (imagine if the base reserve fluctuated up then back down). Do you have any ideas about how to avoid this situation?
We could shift to reasoning in terms of native contribution towards the reserve for specific sub entry types. Then the account just needs to cover the difference if needed. I think for this to work, we'd have to break down the base reserve calculation to something like (instead of a calculation based only on counts):
* total_base_reserve = Sum over categories( count*BASE_RESERVE - min(count*BASE_RESERVE, amount_sponsored(category))) // where categories = sponsored_categories \union non_sponsored_category
Btw, what https://github.com/stellar/stellar-protocol/blob/master/core/cap-0031.md#sponsorship-entries-always-provide-a-full-reserve is incompatible with this and is a justification for hoarding sponsorships to get around the base reserve increase.
Couple things here:
> > Any reason to not make references to assets in Trustline, offers optional as to match on anything? (this probably depends on relaxing the "in use" rule)
> There is a very important technical reason for this. Determining the number of sponsored reserves is equivalent to solving an instance of bipartite https://en.wikipedia.org/wiki/Maximum_cardinality_matching so we have to guarantee that every possible instance can be solved efficiently. The sponsorship descriptors in my proposal make the solution trivial (the instances become so simple, it is hard to even consider it as maximum cardinality matching). Allowing optional constraints makes this much harder. It would be possible for trust lines and signers, which have only one "wild-card", but it would be basically impossible for offers as they have two. That being said, I don't see the value of an optional asset for trust lines. But as Leigh has pointed out, it could be valuable for signers to allow specifying the specific signer.
I was focusing on the question before going into implementation. In particular, if we drop offers from this proposal, it seems we can allow this for all types.
I guess if you don't agree, I'll turn it the other way: why should we support unbounded signer sponsorship?
> > why not allow more than 1 sponsorship per entry? Signers, Data(?), Offers could benefit from a counter.
> I discussed in https://github.com/stellar/stellar-protocol/blob/master/core/cap-0031.md#sponsorship-entries-always-provide-a-full-reserve why I think that this adds complexity without adding much functionality. Do you disagree with the analysis there, or see some benefit that is not clear to me?
I think you were trying to point to https://github.com/stellar/stellar-protocol/blob/master/core/cap-0031.md#why-do-sponsorship-entries-sponsor-reserve-for-only-a-single-ledger-entry ?
I guess the limitations derive from certain choices you made that are in flux (for example, if we use "sponsored reserve"). We can resolve this question later.
(From the "removeSponsorshipOp" section)
> > 5 makes it impossible to transfer sponsorship
> I don't really understand why you would want to transfer sponsorship. If you do not control both accounts, then why would the other party take on the cost of the sponsorship since? If you do control both accounts, then why does it matter which account is associated with the sponsorship? We could always add a TransferSponsorshipOp if we think this is actually useful.
This is a bit backward: there should be justification for any constraint that we put in the system otherwise we're placing limits on things based on how we think those will be used, potentially closing the door to interesting scenarios that we're not smart enough to predict.
Anyways, this is more evident for unbounded sponsorships like signers or offers:
Imagine an account that has a relationship with 2 exchanges, and each exchange provides sponsorships of "up to 2 offers" (or something like this). If the account only has 2 offers, I don't see a reason to stop either exchange from changing their contract to "up to 1 offer" or even stop sponsoring offers (if the account stops being a client of that exchange let's say).
> > 6 makes it impossible to stop sponsoring something
> There are several reasons why I think this is a feature, not a bug.
> 1. Any user of this feature who assumes that they will definitely be able to get their sponsorship back is wrong. It is clear that no proposal can allow a sponsorship to be removed if it would cause the account to have insufficient reserve (after accounting for other existing sponsorships). If this were permitted, then you could simple create a sponsorship, create the sponsored entry, then remove the sponsorship which would circumvent the reserve requirement entirely. So let's assume we have a proposal where it is possible to remove a sponsorship if the account would still have sufficient reserve. This implies that the account has a non-zero available balance of native asset at the time the sponsorship is removed. But an account that currently has no available balance of native asset can unilaterally prevent this by executing the following transaction: send 1 base reserve from another account, add an offer selling an asset issued by this account for (INT64_MAX - reserve) native asset at a price 1:1. The account now has no available limit of native asset so it cannot receive any, no available balance of native asset so no sponsorship can be removed, and the offer cannot be taken.
> 2. But perhaps you think the above example is an arcane edge case that won't really happen in practice. So what happens when an account does enter a state in which it is possible to remove a sponsorship? Well, every sponsor will attempt to remove their sponsorships (one per transaction). But this is a race: most transactions will fail, and the sponsors that submit more transactions are more likely to succeed. This is obviously wasteful, and the incentives are bad.
> 3. What about malicious actors? They could sponsor entries and strategically remove the sponsorships in order to make transactions fail. This would probably necessitate adding a "disable sponsorships" mechanism like you mentioned, which is unnecessary in my proposal as written because receiving a sponsorship is no different from receiving a payment.
Sorry, I am having a hard time understanding 1&2 in this context: you're saying we should not allow to stop sponsoring because we can't guarantee that it can be done (1) or that many sponsors would for some reason decide to stop sponsoring the same account (2). Neither of these seem to be deal breakers to me for having this functionality: (1) seems totally acceptable and (2) seems like an edge case not worth dealing with.
3 is interesting, and is actually a problem even without this property (so we may have to have that flag or some other mechanism anyways?):
Expanding on what "transactions may fail" means, an attacker can make certain operations (like native payments) fail during consensus, but also put the account in a "wedged" state (not enough balance to pay for fees), where it needs to be rescued by some other account (either via a payment of sponsorship).
The thing about 3 is that if the semantics are clear (sponsors can go away at any time if you have the balance), then the code client side can actually deal with this, so we end up with better handling of the edge cases as well (going back to what needs to be done here: flag or information on sponsorship that the client can use are candidates).
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAG4FKhwuk5UvJ3OhV3xR3ozULyvuivvHapTPw%3DEF%2Bf_W0zQczg%40mail.gmail.com.
require signers sponsorships to be specific
If there's only one signer and someone wants to transition away they need to remove and add a signer at the same time. There's no way to free up the sponsorship.
> To unsubscribe from this group and stop receiving emails from it, send an email to stell...@googlegroups.com.
>
> To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/e9707d27-e833-4011-bc2b-1bf585b570c7%40googlegroups.com.
>
>
>
>
>
>
> --
>
> You received this message because you are subscribed to the Google Groups "Stellar Developers" group.
>
> To unsubscribe from this group and stop receiving emails from it, send an email to stell...@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Stellar Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAG4FKhycnUsUHcyjUg-5N4tDhvRMGeXWTgQAyxENjppruTnRJQ%40mail.gmail.com.
Hey everyone,
Based on all of the excellent feedback here and some other conversations, I have prepared a new proposal for a similar mechanism https://github.com/stellar/stellar-protocol/blob/master/core/cap-0033.md. The new proposal avoids many of the issues in the original proposal by removing the SponsorshipEntry. Instead, sponsorship decisions in the new proposal are made off-chain via a “sandwich approach” analogous to CAP-18.
Again, I would appreciate any and all feedback while we try to make progress on this proposal.
Thanks,
Jon
ClaimableBalanceEntry
Provide an actual diff here as it's supposed to tell us what changes compared to CAP0023
EphemeralSponsorshipEntry, GeneralizedLedgerEntry and GeneralizedLedgerKey
Those are not part of the protocol for now. I would move this to an appendix as it seems to be an implementation detail of how "ephemeral" entries could be added and integrated.
Related to this, LedgerEntryType should probably not be changed to include EPHEMERAL types as well. On the implementation side, I'd recommend not using small numbers like "5" in the protocol spec to avoid creating gaps in LedgerEntry types (ie, use negative numbers for ephemeral types seems like an option and just document that "negative numbers are reserved" in the protocol spec).
That said, on the implementation front there are probably better options: we can create a type that wraps LedgerKey / LedgerEntry without having to extend enums which doesn’t require any coordination between protocol spec and implementation.
ManageSponsorshipOp
I'd recommend making the management of ephemeral entries stricter:
Reason for this is that it makes it easier to validate and co-sign; and it leaves the door open to more complex sponsorships semantics in the future if we ever need them (like if we need to allow multiple sponsorships we'd want to create multiple ephemeral entries for the same thing at the same time).
Also, porting from the previous proposal: we should probably not allow accounts to sponsor themselves. It's at best a mistake, and probably makes implementations more complex.
RevokeSponsorshipOp
I see that you're checking `if AvailableBalance(source, NATIVE) < requiredReserve` - but it's probably better to use the generic code (that you're probably going to use in other places) to see if we should sponsor that entry (if there is an ephemeral key in place that makes it happen). Of course in this case we would not update the number of sponsored entries.
Other Operations
Should it be possible to sponsor an entry after it's created? If so, we probably need a new `SponsorEntryOp` that takes a ledger key as parameter.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAG4FKhzryfLUqQsDH42_g9yeC0P%2B-JD2jqSXpZpDsJdHx%3DTXZQ%40mail.gmail.com.
ClaimableBalanceEntry
Sure, I’ll add a diff.
EphemeralSponsorshipEntry, GeneralizedLedgerEntry and GeneralizedLedgerKey
Good idea to move this all to an appendix. We should discuss more about the exact implementation details on GitHub, since it will depend a lot on specific factors in stellar-core and specifically in LedgerTxn.
ManageSponsorshipOp
Making replace return an error is fine by me, I had actually considered that while I was drafting it. I agree it opens the window for more complex semantics in the future. If we go this route, then I think we should make it extremely strict. Deleting a sponsorship that doesn’t exist should also be a failure, in my opinion.
As for changing the parameterization, I think this is purely a matter of aesthetics and user experience. I’m not that picky about it. One design that I had considered was to use “AccountID* sponsoredID”. This is similar to your boolean to determine whether it is create or delete. In this context the behavior would be “delete current sponsor” if sponsoredID is not set, “create the sponsor” if sponsoredID is set (and it is not currently sponsored), and invalid if sponsoredID is set to the source account. Let me know if you are happy with this.
RevokeSponsorshipOp
This is an excellent point. I didn’t consider the following situation: some account is sponsoring future reserves for B when a sponsorship is revoked. Good catch.
Other Operations
I don’t hold a strong opinion about whether or not this should be possible. I can’t currently see a good use for it, but of course that doesn’t mean that there isn’t one. We should probably wait to see if people want this feature, and if so plan it for a future protocol upgrade. In order to maintain the strong backwards compatibility guarantee mentioned in “Why Should Sponsorship be Ephemeral?” we would need to make it contingent on the ManageSponsorshipOp sandwich, so that both sponsoring and sponsored accounts must sign.
Best,
Jon
An EphemeralSponsorshipEntry can be created, modified or deleted only by the ManageSponsorshipOp. Sponsored reserves can be reclaimed under some conditions by RevokeSponsorshipOp.
struct AccountEntryExtensionV2
{
uint32 numSponsored;
SignerSponsorship signerSponsorships<20>;
};
This applies even in the case of sponsorship for CreateAccountOp, whereas CreateAccountOp can usually be used without a signature from the created account.
operations[2]:
sourceAccount: A
body:
type: MANAGE_SPONSORSHIP
accountID: A
To unsubscribe from this group and stop receiving emails from it, send an email to stell...@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/940b0726-79e2-49ec-9d9e-d68df6c2437f%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAAr2UCyDPJjqmsqPPB2Xjz3bEaa8tGCwG8sYUuo8Oq5zBD8Wpg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/940b0726-79e2-49ec-9d9e-d68df6c2437f%40googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Stellar Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stell...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAAr2UCyDPJjqmsqPPB2Xjz3bEaa8tGCwG8sYUuo8Oq5zBD8Wpg%40mail.gmail.com.
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/5538cf5c-ed7a-4622-bb36-770df7cdb867o%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/5538cf5c-ed7a-4622-bb36-770df7cdb867o%40googlegroups.com.
Another approach to making SEP-30 compatible with CAP-33 would be to allow sponsorship operations to have other source accounts, on the assumption that the sponsor account is not a registered account of the SEP-30 servers. This is an unintuitive feature though that if a sponsor was not aware they could make their account vulnerable to others utilizing their sponsorship capabilities without their authorization.
After submitting my previous comment, I realize the base reserve was to keep the ledger smaller and not prevent network transaction spam.I still think it you should reduce the financial load of sponsoring many accounts.Like if the source funding is large enough the base reserve amount is reduced by a percentage.Sincerely,Carson FlintOn Wednesday, July 1, 2020 at 7:18:17 AM UTC-4 Carson Flint wrote:Again, correct me if I am wrong, but I believe the whole point of the minimum reserve is to prevent network spam.If so, would it make sense to rate-limit sponsored accounts?For example, you sponsor an account with an amount less than the minimum reserve and thus the account becomes rate limited accordingly.Sponsor account with 1 stroop = account can make one operation every 48 hoursSponsor account with 0.2 xlm = account can make one operation every 30 minutesetcSincerely,Carson Flint
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/da3b644f-65e5-4e4c-8800-3dee477b378bn%40googlegroups.com.
I want to continue the conversation from the Open Protocol Meeting on 7/9 regarding the appropriate predicate structure. Some options and preliminary thoughts on them:- Unlimited recursion in XDR but limited to a certain depth in validation logic. Advantage: it is the most flexible, and easy to implement. Disadvantage: it requires special validation logic, malicious infinite recursion, and can be the hardest to reason about- Limited recursion in XDR. Advantage: it is the most flexible, no malicious infinite recursion, and doesn't require special validation logic. Disadvantage: it can be hard to work with (many different similar structures), and can be the hardest to reason about- XDR-opaque. Advantage: it is the most flexible, and no malicious infinite recursion. Disadvantage: less performant (requires additional marshalling), requires special validation logic, and can be the hardest to reason about- Disjunctive Normal Form. Advantage: it is the simplest to reason about, easy to implement, and no malicious infinite recursion. Disadvantage: less flexible, less space efficient (accountIDs are large relative to predicates)There are probably a few other possibilities in this space too. For example, Bartek proposed an RPN approach which was conceptually interesting to me but Graydon opposed.
The other open question from the meeting is whether we should support predicates like `_BEFORE` and `_AFTER` or have a generic `_NOT`. `_NOT` is elegant in the sense that it doesn't require a lot of duplication, but some predicates such as revealing a hash-preimage don't make a ton of sense with `_NOT`. Thoughts?
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/CAG4FKhx7NsEJ_WVWdP%2BKJ77kPZmKonyhv_PwRFB2M0edhH0oOg%40mail.gmail.com.