-
Notifications
You must be signed in to change notification settings - Fork 20
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
Index servers are too optimistic (fees not accounted for) #195
Comments
I would happily work on this (or at least try). It seems to me that there are two main approaches, both requiring a reverse-BFS, but with quite different APIs and capabilities:
|
@amosonn: Hi, thanks for helping out! I would go with 1.i. I tried to think about 1.ii for a while, I can't understand it. how do you pass all the fees in the graph using an iterator? If you only pass an iterator for fees along a route, how can you select that route ahead of time (Before finding that route?)?
It's an interesting problem indeed. BFS with weighted distances turns into Dijkstra. I wonder if reverse dijkstra is a correct solution, or something is still missing. I haven't thought about it yet. @pzmarzly : I hand this over to Amos. I promise to arrange you something at least as interesting as this one (: |
I don't want to step on any toes, if @pzmarzly already started working on this, I'll find something different :) In general, for all of these solutions, it seems to me that a reverse-BFS or reverse-Dijkstra (we actually need something more complicated with a heap, since we want to return all routes, but it should still work) should work just as well as the forward ones. If you look at this as searching for a path to transfer debt along, this is exactly symmetric to looking at a path to transfer credits along. Like transferring holes instead of electrons. Regarding 1.ii., I meant something along the lines of |
I haven't, I'll gladly leave this issue to you |
Digging deeper, I arrived at another question: do we want these extra arguments to be passed over from the client as part of the request (updating |
Yet another thought: who says the sender should be paying the fees? It's probably the easiest choice, other options have other considerations: if the receiver pays them, for instance, the sender has no interest in choosing a short path; if they split them half-half, finding a good path becomes even more complicated. Still, I would say that supporting such other schemes might be something to future-proof against. Under the current protocol, can the receiver easily check what was the original amount transferred by the sender? |
I forgot something very useful: There is a full and up to date design diagram of Offst here:
I assume that by extra arguments you mean the fees that will be paid to each node along the way. If in the future we decide for more flexible fees we can modify more things. Doing the change in
I dedicated a long time to think about who should pay the fees, my short answer is that I believe we should never allow this option, and only the sender pays the fees, mostly due to safety considerations. My main objection follows: Consider this diagram:
B wants to get credits for free. How to do this?
There aren't real node there, but B can make it appear very real. From the point of view of E, the amount of fees paid in this transaction is 99 + 1 + 1 = 101 credits. So E will give about 10 credits.
Yes, I'm quoting from the new proposal. struct RequestSendFundsOp {
requestId @0: Uid;
# Randomly generated reqeustId [128 bits]
srcHashedLock @1: Hash;
# sha512/256(srcPlainLock), where srcPlainLock is of size 256 bits.
route @2: FriendsRoute;
# A route of friends that leads to the destination
destPayment @3: CustomUInt128;
# Amount of credits to pay the destination
invoiceId @4: InvoiceId;
# A 256 bit value representing the invoice this request
# intends to pay.
} This is the first message arriving from the sender to the receiver (along the route).
I never managed to find a safe way to make the receiver pay the fees, therefore I propose to go with the simple implementation. As a side note, you probably saw that the index server has a super naive implementation at this point:
Until we see real adoption I wouldn't bother dealing with those things at all (unless you really enjoy it) |
Thanks for the detailed response! I definitely felt there were funny things going on when the receiver pays fees, but I didn't think about making up nodes. This indeed seems broken enough that we shouldn't consider it an option. This also means that it makes less sense for the client to pass the required fees to the server; seems more likely that the server will know better what fees are needed (e.g. in a case where nodes have custom fees). So for now, I will not pass any new argument, not even the required fixed fee, and leave that all to the server. This is definitely easier to implement ;) Regarding the server implementation, I'll look around, if I see something low-hanging I'll change it, maybe in a different PR. Regarding the new proposal, I read it, but didn't feel I had something to say. Maybe this means I haven't looked at it enough :) I think I have now enough info to start writing. |
@amosonn : As part of the redesign I plan to support more flexible transaction fees (According to ideas of yours and @SonOfLilit). I realize that you might have already done some work, and highly apologize for changing my mind, possibly rendering some of your work irrelevant. If you think that the scope of this issue becomes too broad, don't worry, I can start writing a very basic prototype for the Index Server and if you want you could do the cool graph stuff when the API around stabilizes. I write here my general ideas for changes. If you ever have time to check it out please tell me what you think. Fees parametersMy general idea was to let any node specify two values: a multiplier Example:
C can configure Protocol changesThe part of the protocol that I expect to change is the communication between Node (Index Client) and Index Server. The rest of the protocol message will only have the results of the fees computation, and not the values Some important changes:
As an example, consider the route:
If B requests a route to E, he could get a route of the following form from the index server:
One thought I had is to not supply the Multiplier implementation detailsI plan to have
I'm still not sure about the Gradual fees increaseIf a node increases his fees along some edge, it is likely that the next few transactions along that route will fail because the payers use old information about the fees along that edge. Therefore whenever a node wants to increase his fees (An increase in |
I'm beginning to think fees should be totally out of band (as in, you don't
publish your fees in this protocol, big nodes use a BGP like thing among
themselves and private users get an API from their "bank" to ask what fees
they need to pay to each node along the way, and probably an agreement
about the sum of these fees). You can just specify how much you're offering
to give to each node along the way and they either accept the transaction
or don't.
…On Tue, May 14, 2019 at 1:56 PM real ***@***.***> wrote:
@amosonn <https://github.com/amosonn> : As part of the redesign I plan to
support more flexible transaction fees (According to ideas of yours and
@SonOfLilit <https://github.com/SonOfLilit>). I realize that you might
have already done some work, and highly apologize for changing my mind,
possibly rendering some of your work irrelevant.
If you think that the scope of this issue becomes too broad, don't worry,
I can start writing a very basic prototype for the Index Server and if you
want you could do the cool graph stuff when the API around stabilizes.
My plan is to start from the core (the Funder) and extend changes outside
all the way to the communication protocols and API, so it could take a
while.
I write here my general ideas for changes. If you ever have time to check
it out please tell me what you think.
Fees parameters
My general idea was to let any node specify two values: a multiplier 0 <=
m < 1 and an adder n for every outgoing edge. The fees paid for pushing
credits along that edge will be mx + n.
Example:
B -- C -- D
C can configure m_{CD} = 2^-9 and n_{CD} = 5. If B wants to send a
payment of 512 credits to C, then 512 * (2^-9) + 5 = 6 of fee credits will
be paid to C.
Protocol changes
The part of the protocol that I expect to change is the communication
between Node (Index Client) and Index Server. The rest of the protocol
message will only have the results of the fees computation, and not the
values m and n themselves.
Some important changes:
- During a route request, the Index server should also get the amount
of credits to be sent to find a cheap route (Because of the added
multiplier value, the fees depend on the amount of transferred credit).
- Index server could allow fragmented multi route payments (See here
<https://github.com/freedomlayer/offst/blob/1aeae7f2f079b8ca462d7d4cc76935cb9c1f3985/doc/docs/atomic_proposal.md#fragmentedmulti-route-transactions>
for more details). This means that a node could ask for a 100 credits
route, and he will get back 5 routes that together allow to send 100
credits.
- The returned route should contain the fees parameters (m,n) for
every intermediate edge.
As an example, consider the route:
B -- C -- D -- E
If B requests a route to E, he could get a route of the following form
from the index server:
When B asks for a route from B to E, B will get the following:
B, (C, m_{CD}, n_{CD}), (D, m{DE}, n_{DE}), E
One thought I had is to not supply the (m,n) values and instead only show
the calculated sum of expected transaction fees, but I tend to decide
against it because it allows less flexibility for the application.
Multiplier implementation details
I plan to have m of type u64, which always represents a fractional value
between 0 (inclusive) and 1 (non inclusive). Computing the multiplication
mx can be done using fixed point arithmetic, rounded to the lower value:
floor(m * x / (2^64))
I'm still not sure about the floor decision. What do you think?
Gradual fees increase
If a node increases his fees along some edge, it is likely that the next
few transactions along that route will fail because the payers use old
information about the fees along that edge. Therefore whenever a node wants
to increase his fees (An increase in m or n) along an edge, it would be
better if it first sends the increase to the Index Server, wait for a while
and only then send the update to the Funder.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#195>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAADU7KDSZX6DQAFLBVVCU3PVKLHBANCNFSM4HKZNHGA>
.
|
The reason for this is that among big players, they'd want to calculate
their counterparty risk and ask different fees from different nodes at
different times (if you have a lot of debt, your interest rises).
…On Tue, May 14, 2019 at 2:33 PM Aur Saraf ***@***.***> wrote:
I'm beginning to think fees should be totally out of band (as in, you
don't publish your fees in this protocol, big nodes use a BGP like thing
among themselves and private users get an API from their "bank" to ask what
fees they need to pay to each node along the way, and probably an agreement
about the sum of these fees). You can just specify how much you're offering
to give to each node along the way and they either accept the transaction
or don't.
On Tue, May 14, 2019 at 1:56 PM real ***@***.***> wrote:
> @amosonn <https://github.com/amosonn> : As part of the redesign I plan
> to support more flexible transaction fees (According to ideas of yours and
> @SonOfLilit <https://github.com/SonOfLilit>). I realize that you might
> have already done some work, and highly apologize for changing my mind,
> possibly rendering some of your work irrelevant.
>
> If you think that the scope of this issue becomes too broad, don't worry,
> I can start writing a very basic prototype for the Index Server and if you
> want you could do the cool graph stuff when the API around stabilizes.
> My plan is to start from the core (the Funder) and extend changes outside
> all the way to the communication protocols and API, so it could take a
> while.
>
> I write here my general ideas for changes. If you ever have time to check
> it out please tell me what you think.
> Fees parameters
>
> My general idea was to let any node specify two values: a multiplier 0
> <= m < 1 and an adder n for every outgoing edge. The fees paid for
> pushing credits along that edge will be mx + n.
>
> Example:
>
> B -- C -- D
>
> C can configure m_{CD} = 2^-9 and n_{CD} = 5. If B wants to send a
> payment of 512 credits to C, then 512 * (2^-9) + 5 = 6 of fee credits will
> be paid to C.
> Protocol changes
>
> The part of the protocol that I expect to change is the communication
> between Node (Index Client) and Index Server. The rest of the protocol
> message will only have the results of the fees computation, and not the
> values m and n themselves.
>
> Some important changes:
>
> - During a route request, the Index server should also get the amount
> of credits to be sent to find a cheap route (Because of the added
> multiplier value, the fees depend on the amount of transferred credit).
> - Index server could allow fragmented multi route payments (See here
> <https://github.com/freedomlayer/offst/blob/1aeae7f2f079b8ca462d7d4cc76935cb9c1f3985/doc/docs/atomic_proposal.md#fragmentedmulti-route-transactions>
> for more details). This means that a node could ask for a 100 credits
> route, and he will get back 5 routes that together allow to send 100
> credits.
> - The returned route should contain the fees parameters (m,n) for
> every intermediate edge.
>
> As an example, consider the route:
>
> B -- C -- D -- E
>
> If B requests a route to E, he could get a route of the following form
> from the index server:
> When B asks for a route from B to E, B will get the following:
>
> B, (C, m_{CD}, n_{CD}), (D, m{DE}, n_{DE}), E
>
> One thought I had is to not supply the (m,n) values and instead only
> show the calculated sum of expected transaction fees, but I tend to decide
> against it because it allows less flexibility for the application.
> Multiplier implementation details
>
> I plan to have m of type u64, which always represents a fractional value
> between 0 (inclusive) and 1 (non inclusive). Computing the multiplication
> mx can be done using fixed point arithmetic, rounded to the lower value:
>
> floor(m * x / (2^64))
>
> I'm still not sure about the floor decision. What do you think?
> Gradual fees increase
>
> If a node increases his fees along some edge, it is likely that the next
> few transactions along that route will fail because the payers use old
> information about the fees along that edge. Therefore whenever a node wants
> to increase his fees (An increase in m or n) along an edge, it would be
> better if it first sends the increase to the Index Server, wait for a while
> and only then send the update to the Funder.
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#195>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAADU7KDSZX6DQAFLBVVCU3PVKLHBANCNFSM4HKZNHGA>
> .
>
|
Hey, thanks for jumping by! The proposed design above should allow anyone to set fees in a secure way (Setting different fees for different friends), and also dynamically change those fees in-band. This is not a very difficult modification for us to do. I really want to give the abilities to do those things to everyone, not only big players. Do you see any problem that could occur by doing that?
Do you actually mean interest here, or just commission for a transaction? I see those two as different things. Commission is taken only when a transaction happens, while interest has a relation to the passage of time. About adding interest, I still have no idea how to implement it in a sound way, so having it in-band is out of the question for me at least for the next development iteration. |
Sorry, I totally missed the "for every edge". I take everything I said back.
To my understanding, if you're a business you have a cost of running your
business (e.g. salaries, server costs which are almost O(1), cost of
capital which is O(money transferred) and you'll set prices so that the sum
of incoming money equals the costs + some margin percentage (which will in
general be lower the more competition there is and lower the more customers
are price sensitive). The split can happen in any possible way (one
customer who doesn't care about price could subsidize all other customers,
etc'), but it's my understanding that it's always better for society when
prices are split in a way that reflects marginal cost (so if making more
transactions doesn't cost the company more but making the same amount of
transactions with higher amounts costs linearly more, you'd want prices to
depend linearly on transaction size, etc').
Since end users will probably want simple predictable costs and will be
required at least at first to deposit money up front (so no credit risk),
their "first node" will want to offer them simple predictable fees (you
will always be able to make a transfer for max(0.1$, 0.1%), I will just
tell you how to distribute that between the nodes on the path according to
agreements I have with my peer nodes and they have with theirs).
Between middlemen nodes, their cost is credit risk and opportunity cost for
doing other things with the money they're locking up in temporary loans.
Therefore, I expect them to charge each other no transaction fees but to do
charge interest (different per node, more or less linear with amount and
with time).
In the current banking system, the cost of making transfers is mostly O(1)
for setting up the system, so it needs to be split somehow between all the
customers. Inside Israel it tends to be a flat fee for reasonable transfer
amounts (until 100k or so if I remember correctly). Between countries
there's a percentage fee with a minimum (you must pay at least $10) and a
maximum (pay at most $1000). Banks also make you pay $25 from your pocket
to any middleman node, and won't tell you in advance how many middle nodes
there are (!!!). TransferWise and other transfer startups take a percentage
fee, I don't remember min or max. They usually hide it in the currency
exchange spread and call it "no commission".
…On Tue, May 14, 2019, 4:23 PM real ***@***.***> wrote:
The reason for this is that among big players, they'd want to calculate
their counterparty risk and ask different fees from different nodes at
different times
Hey, thanks for jumping by! The proposed design above should allow anyone
to set fees in a secure way (Setting different fees for different friends),
and also dynamically change those fees in-band. This is not a very
difficult modification for us to do. I really want to give the abilities to
do those things to everyone, not only big players. Do you see any problem
that could occur by doing that?
(if you have a lot of debt, your interest rises)
Do you actually mean interest here, or just commission for a transaction?
I see those two as different things. Commission is taken only when a
transaction happens, while interest has a relation to the passage of time.
About adding interest, I still have no idea how to implement it in a sound
way, so having it in-band is out of the question for me at least for the
next development iteration.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#195>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAADU7NN6XNNMQGE72TK4IDPVK4O7ANCNFSM4HKZNHGA>
.
|
@realcr The changes I've started doing were mostly around, and not directly related to the implementation of the issue, so no worries there :). The entire change is probably too large for one PR, and it'd be good to split it up into several sub-tasks. The question is, whether implementing the original plan for this issue is a good first step. My current plan for implementation was to strip down the interface of I can see two possible interfaces here, one where Just one more consideration, which makes the entire thing more complicated - especially in view of multi-route payments: once you switch over to fees of form Either way, one could argue, that in this case, it would be best to delegate the problem of optimization to the client, which it may solve in different ways. This alleviates the computational stress from the index server, but in turn, requires much more bandwidth (the server needs to notify the client of "all", or several, possible routes). I'm not sure what's the best way to make progress here, this probably depends on how complicated is this problem actually. |
I forgot to tell you, I bumped rust nightly version in use. Make sure to rebase everything and update your local rust nightly version. You can always find the current version at .travis.yml.
I agree. What I had in mind is (roughly) the following communication between the node and index server:
As the index server is given the amount of credits the node wants to send, it can have total ordering ordering of all the routes. I wrote multi-route above as a general name for both routes and multi-routes. I am still not sure if it's a good idea I am not sure if it's a good idea that the index server will deal with multi routes, but I think that it could be cool if no single route is available, and I could instead get a multi route from the index server. Thinking about it, the index server is in the best position to compose a multi route, the node knows too little to do this efficiently. Another possibility which I think you have mentioned is to let the index server only deal with single routes, and let the node compose his own multi routes. I currently vote about letting the index server calculate multi routes, but I'm not fully sure about this. I haven't thought at all about what would be a good algorithm to put at the index server, but I'm sure we can figure it out. (It sounds like the fun part to me at least).
I think that I managed to get rid of I expect the index server to take periodic updates of capacities and rates ((multiplier, adder) pairs), wait for requests from nodes and respond with good routes (or multi-routes). I'm still thinking about it, it might be reasonable that the index server will return all the (multiplier,adder) pairs for the route as well, this might allow the client reuse the route in some other way if he ever wants to. |
It doesn't necessarily need to return all the Regarding algorithms: I think you need to run a strange Dijkstra, that stores a few layers of Pareto front at each node along the way; and then once you have the Pareto front for the destination node, you can solve some kind of (continuous?) knapsack to determine the best mixture. Why a few layers? Because you need to have the maximum capacity (up to the requested amount) available, even if this means selecting sub-optimal (i.e., not on the first Pareto front) route. I think that maintaining a Pareto front at each vertex should be easy, i.e. a simple modification to the Dijkstra, because adding them is simple. I'm not sure about the multi-layered Pareto front. I saw the nightly thing, I will rebase, and also look at what you changed in the Funder :). |
You are right! What a helpful fact this is (:
I trust you that you are doing the correct thing here. Changing into the new atomic payments design takes all my time right now. I should look up Pareto front later and recall how it works. In any case, you should know that even having a much less than computationally optimal solution will be great. Everything above it is extra.
If you are referring to PR #199, please note that it doesn't fully compile. I did manage to make the core payment algorithms (mutual_credit) compile and pass the tests with the new atomic payments design, but porting everything around it will take me some time for sure, maybe even a few weeks. |
Hopefully we have got this covered with the new proposal for affine fees:
With the proposed design the buying experience for an end user should be as follows:
This somehow breaks the rule of "simple and predictable" fees for the end user, but at least the user always knows before the payment happens exactly what the fees are going to be. |
Since most end-users are going to have a "bank" node always be their first
node, I think we should allow that bank node to offer the user static fees
and take up the difference.
…On Sat, May 18, 2019, 8:27 PM real ***@***.***> wrote:
@SonOfLilit <https://github.com/SonOfLilit> :
so if making more transactions doesn't cost the company more but making
the same amount of transactions with higher amounts costs linearly more,
you'd want prices to depend linearly on transaction size, etc'
Hopefully we have got this covered with the new proposal for affine fees: m*x
+ n fees for a transaction of size x credits, where 0 <= m < 1 and n are
fully configurable for every directed edge.
Banks also make you pay $25 from your pocket to any middleman node, and
won't tell you in advance how many middle nodes there are (!!!)
With the proposed design the buying experience for an end user should be
as follows:
- You pick an item you want to buy.
- You click on buying and then a cheapest route is chosen for you. The
route determines the fees.
- You get to choose if you agree to the fees or not.
This somehow breaks the rule of "simple and predictable" fees for the end
user, but at least the user always knows before the payment happens exactly
what the fees are going to be.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#195>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAADU7OIFWOQ66L4YBQ4GCLPWA37FANCNFSM4HKZNHGA>
.
|
I'm sorry, apart from thinking more about the design, I haven't had time to make much progress on this, and the next two weeks I'll be away. I'll be happy to continue after that, but if this is deemed too long, and someone else wants to pick this up in the meantime, that's fair. |
@amosonn : No worries, have fun on the two weeks! The new protocol supports payments using multi routes with
@SonOfLilit : Your last piece of advice helped me make some decisions on how the fees work on the protocol, it was very useful. Thanks! I made sure that with the correct configuration you can get the effect of user static fees. |
Closed in favor of issue #218. |
Index servers
Index servers do mainly two things:
Problem with current implementation
The current implementation of Index servers is too optimistic, because index servers do not take into account the fees for sending credits along routes.
For example, with the current implementation, if a node B wants to send 10 credits to a remote node E, the following route may be proposed:
Where the available capacity is as follows:
A route with exactly those capacities for sending credits is not sufficient for passing 10 credits, because fees needs to be paid to the intermediate nodes. Therefore, at least the following available capacities are required:
The implementation of the Index servers needs to be updated to take into account the payment fees to mediators.
Relevant code
The relevant code is at:
components/index_server/src/graph/simple_capacity_graph.rs
, which relies on the implementation atbfs.rs
.The current implementation relies on running a BFS algorithm to find a path of certain capacity from a source node to a destination node. We need to take into account the fees to the transaction mediators in this search algorithm.
Other relevant code is somewhat far away, at
components/funder/src/credit_calc.rs
. This is the piece of code that contains the actual calculation for fees to mediators during a transaction. The crate offst-index-server should not have the crate offst-funder as a dependency, so maybe it could be a good idea to move credit_calc.rs to offst-proto, possibly now or in the future.Proposal for solution algorithm
It might be possible to start a graph search algorithm that goes backwards (From the destination back to the source). The search algorithm can be somewhat like BFS, but we need to make sure that doing something like this is actually sound, and we can't possibly miss valid routes or return wrong routes.
How to work on this
This is a task that requires some prior research. Please write a short proposal of what you intend to do before you start coding, hopefully I might be able to say something useful that could help you out.
The text was updated successfully, but these errors were encountered: