Skip to content
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

docs: introduce ledger-ledger lotocol #251

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions asn1/LedgerLedgerLotocol.asn
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
LedgerLedgerLotocol
DEFINITIONS
AUTOMATIC TAGS ::=
BEGIN

IMPORTS
UInt8,
UInt32,
UInt64,
UInt128,
UInt256
FROM GenericTypes

Address,
Timestamp
FROM InterledgerTypes
;

SideProtocolData ::= SEQUENCE OF SEQUENCE {
protocolName IA5String,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any examples of what this might be?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were talking with @jimmiebfulton and @sappenin about cases where you might want to encode rules related to a certain payment, like ledgers the payment should not be routed through. In the JS ledger plugin interface this kind of side protocol would be included in the transfer's custom field. They brought up a good point that that information might be relevant to quoting as well. We figured we might as well put this type of extensibility in all of the messages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would also be useful for sending payment channel claims

protocolData OCTET STRING
}

MessageRequest ::= SEQUENCE {
packet InterledgerPacket,
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

MessageResponse ::= SEQUENCE {
packet InterledgerPacket,
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

TransferRequest ::= SEQUENCE {
transferId UInt128,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could also use the condition as a unique id of the transfer?

Copy link
Contributor

@michielbdejong michielbdejong Aug 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i vaguely remember this was to allow friendly repeated attempts at the same payment, but now don't see why you couldn't do the same thing using just (repeated) condition.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforcing condition uniqueness would also prevent you from doing things like Optimistic over Universal (which might not be a good idea anyway)

amount UInt64,
condition UInt256,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why rename executionCondition to condition?

expiresAt Timestamp,
packet InterledgerPacket,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of including an InterledgerPacket here, with an InterledgerProtocolPayment inside it, and a useless type field that will always be 1, we should maybe directly include the InterledgerProtocolPayment itself here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should do that because there may be other versions of the InterledgerProtocolPayment packet later, and we could also decide to do things like sending quote requests on transfers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, good point. I removed this from #256 (comment) (which I am now quite starting to like as I look at it again, actually).

-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

TransferResponse ::= SEQUENCE {
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

FulfillRequest ::= SEQUENCE {
transferId UInt128,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or condition

fulfillment UInt256,
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

FulfillResponse ::= SEQUENCE {
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

RejectRequest ::= SEQUENCE {
transferId UInt128,
rejectionReason InterledgerPacket,
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

RejectResponse ::= SEQUENCE {
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

TransferStateRequest ::= SEQUENCE {
transferId UInt128,
Copy link
Contributor

@michielbdejong michielbdejong Aug 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for this to work nicely, it does make sense, i guess, to have a separate id field

-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

TransferStateResponse ::= SEQUENCE {
state CHOICE {
fulfillment UInt256,
rejectionReason InterledgerPacket,
pending NULL,
nonExistent NULL
},
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

BalanceRequest ::= SEQUENCE {
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

BalanceResponse ::= SEQUENCE {
currentBalance VarInt,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should define more precisely, i think the most generic definition would be:

  • + total amounts which you received and peer agrees you have fulfilled in time
  • - total amounts which you sent and peer claims to have fulfilled in time
  • - total amounts which you sent and peer claims to still be pending
  • + total amounts which peer agrees you sent on-ledger (unconditional/fulfilled/paychan-close)
  • - total amounts which peer claims you received on-ledger (unconditional/fulfilled/paychan-close)
  • + total of, for each open outgoing paychan, highest claim peer agrees you gave
  • - total of, for each open incoming paychan, highest claim peer says they gave you

So then:

  • your max send limit is currentBalance-minBalance
  • your max receive limit is maxBalance-currentBalance

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another view is saying settlement can only occur through circular conditional payments to self, "into this trustline", so then this protocol can only be used for one-to-one trustlines, and you only need the first 3 items to describe the balance. Apart from LLL, we would still on-ledger escrow plugins as well as paychan plugins, but they would only be used for the settlement payments, and LLL would be used for the "main traffic".

minBalance VarInt,
maxBalance VarInt,
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

CustomRequest ::= SEQUENCE {
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

CustomResponse ::= SEQUENCE {
-- Additional data for protocol extensibility
sideProtocolData SideProtocolData
}

CALL ::= CLASS {
&typeId UInt8 UNIQUE,
&Type
} WITH SYNTAX {&typeId &Type}

CallSet CALL ::= {
-- All requests MUST use odd typeIds
-- All responses MUST use even typeIds
{1 MessageRequest} |
{2 MessageResponse} |
{3 TransferRequest} |
{4 TransferResponse} |
{5 FulfillRequest} |
{6 FulfillResponse} |
{7 RejectRequest} |
{8 RejectResponse} |
{9 TransferStateRequest} |
{10 TransferStateResponse} |
{11 BalanceRequest} |
{12 BalanceResponse} |
{13 CustomRequest} |
{14 CustomResponse}
}

LedgerLedgerLotocolPacket ::= SEQUENCE {
-- One byte type ID
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe differentiate between request and response so that response can carry an optional error and a response code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are differentiated by each CallSet item either being a request or a response. Note that ILP Errors count as IlpPacket types

type CALL.&typeId ({CallSet}),
-- Allow multiple accounts to be multiplexed on one connection
accountId UInt32,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does account mean "from" or "to", here? Or is it more "prefix"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more prefix

-- Used to associate requests and corresponding responses
-- If requestId = 0, the server MUST not send a response
requestId UInt32,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't this also duplicate the transferId?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They do slightly different things. I could make multiple calls, in which each request/response would have the same requestId, regarding the same transfer. First I would prepare it, which has a request and response, then it would get fulfilled, which has another request/response, and then I could check the state, etc. requestId is meant to correlate a specific call request with its response.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could make multiple calls, in which each request/response would have the same requestId, regarding the same transfer

This doesn't make sense. Do you mean different requestId and same transferId?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry. Same transferId

-- Length-prefixed main data
data CALL.&Type ({CallSet}{@type})
}

END
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is no call to get currency code and scale, where should a ledger plugin for this protocol get that info from? We talked about getting that from some kind of webfinger lookup but does that mean the plugin for this protocol would depend on the webfinger lookup as well, or would those options have to be configured?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's reasonable to remove getInfo and getAccount. There is a lot more you also need to negotiate, like version of this protocol, version of underlying socket protocol, endpoint URL in each direction, and auth tokens. Also, it might be that currency info is only defined relatively (e.g. company stock).