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

Create 0160-dispatch-queue.md #160

Merged
merged 2 commits into from
Nov 24, 2024

Conversation

EmelyanenkoK
Copy link
Member

No description provided.

@EmelyanenkoK EmelyanenkoK changed the title Create 0161-dispatch-queue.md Create 0160-dispatch-queue.md Jun 13, 2024
@akifoq
Copy link

akifoq commented Jun 14, 2024

Although the finalization of A->C->B chain earlier than A->B chain already can occur in the case of non-neighboring shards and thus doesn't directly relate to the dispatch queue proposal, it's worth noting that it can lead to some interesting side-effects. Consider, for example, a contract A which sends a message to a contract B and then (in the same transaction or even in a later one) sends a jetton transfer to the contract B, expecting it to perform some non-trivial logic on transfer notification. Since regular messages are routed directly and jetton transfers are proxied through jetton wallets, it's possible (under heavy load) that the jetton transfer notification arrives earlier than the regular message, likely breaking the assumptions the contract logic is based on. Even worse, such a situation is quite hard to spot during testing phase, since it requires heavy load to occur. And since jetton transfers are one of the main types of transactions, this issue might be quite common in the protocols, remaining hidden until it's too late.

It's not just theoretical considerations -- there already is a popular protocol susceptible to the exact issue. Namely, the liquid staking pool in the "pessimistic deposit-withdrawals mode" firstly deploys a deposit_payout nft-collection, and then (in a later transaction) mints pool jettons to it, initiating the jettons distribution. The collection is expected to perform the distribution logic on the transfer notification, but it might be not deployed yet at that moment. Currently the issue can't occur since all the shards are always neighboring and the dispatch queue proposal is not accepted yet, and it's unlikely to occur even with them, but it could lead to the deposit loss.

Unfortunately, it seems to be yet another drawback of the jetton standard over-complication compared to the (partly unimplemented) native extra currency transfers. It's not obvious how to reliably send a regular message and a jetton transfer to a contract enforcing the right order. The solution might be to delay the processing of the notification in the contract logic until the regular message arrivies or proxy all of the messages through the jetton transfers (doesn't allow to deploy the contract).

Also with the use of "large contracts" mechanics and with a modification to the jetton standard, it's possible to make a jetton wallet always reside in the same shard as the owner account (deploying the wallet with Anycast field, but requiring the first 64 bits of the address to be the same as the owner's bits). It already has the benefit of faster jetton transfers with less cross-shard forwards (not compromising the scalability of the standard), but also seems to always enforce the right order of the messages delivery? (to be further researched)

By the way, the issue can be detected in the future by the help of static analyzers. Consider the two types of events: sending a message and receiving a message. Given the message spawning relation (receiving of a message A causes sending of messages B, C...) and message sequence relation (message A is sent before message B from the same address) it's quite easy to construct the complete logical dependency partial order relation between all the messages using the following rules:

  1. Transitivity: if event E1 always occurs earlier than event E2 and E2 always occurs earlier than E3, then E1 always occurs earlier than E3.
  2. FIFO guarantees: let A, B be messages with the same sender and receiver. If sending of A always occurs earlier than sending of B then receiving of A always occurs earlier than receiving of B.

It seems that these are the only sensible guarantees provided by the blockchain (except for the weird ones involving specifically crafted contract address prefixes). Given the partial order the assertion of receiving a message earlier than another one can be checked. The message spawning relation and the message sequence relation for messages sent at the same transaction can be built by the static analyzer in most cases and the assumptions of a transaction T1 sending messages A, B, C... occurring earlier than transaction T2 sending messages E, F, G... can be provided by the developer. The assumptions and assertions can be even integrated in the programming language used for developing smart contracts.

Redmishiaomi

This comment was marked as spam.

## Dispatch Queue
To balance load, we introduce an additional mechanism called the _Dispatch Queue_. When contract sends a message, it may either enter the Dispatch Queue (before the Collator moves some messages from the Dispatch Queue to the OutMsgQueue later on block collation) or directly enter OutMsgQueue. This intermediate step allows for a more even distribution of load among all dApps running in parallel.

The Dispatch Queue is organized as a set of outgoing message queues for each account. When the collator forwards messages to the OutMsgQueue, it maintains lt-order: a message from Account A with `lt1` will move to the OutMsgQueue before a message from Account A with `lt2` if `lt1 < lt2`. However, this order is not maintained for messages from different accounts. For example, a message from Account A with `lt1 > lt2` may be processed before a message from Account B with lt2 if there is a significant backlog of messages from Account B.

Choose a reason for hiding this comment

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

Hello!

The following sentence is not obvious:

For example, a message from Account A with lt1 > lt2 may be processed before a message from Account B with lt2 if there is a significant backlog of messages from Account B.

Does it mean, that message came with the earlier lt from account A, can be processed after, than message with later lt came from account B? It's strange.

Copy link
Member Author

@EmelyanenkoK EmelyanenkoK Aug 31, 2024

Choose a reason for hiding this comment

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

Yes, it can, but it is not a new behavior actually.

Imagine situation you have shard (0,2000000000000000) and (0,6000000000000000). Then both shard produce blocks with the same lt_start 48840433000000.
Then lets we have accounts A and B in shard (0,2000000000000000) and account C in shard (0,6000000000000000). And lets account A and C creates two messages each to account B with lt 48840433000001 and 48840433000002.

In this case both message A->B will be processed in the same block where it was created, while messages from C will reach account B later (when there will be masterchain block X that reference (0,6000000000000000) and also block in shard (0,2000000000000000) that reference block X).

That leads to the situation when A->B(48840433000002) will be processed earlier than C->B(48840433000001).

The only guarantee we have is that messages of type A->B will be processed in the same order it was sent. This guarantee holds.

Copy link

@mzhumakhanov mzhumakhanov Aug 31, 2024

Choose a reason for hiding this comment

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

Thank you for the details and fast reply! Yes, I agree, intershard transactions need more steps comparing to transactions within single shard and much more often intershard transactions will be processed later than transactions within a single shard.

In particular I'm interested in transactions order within a single block and a single shard. Does dispatch queue have impact on transactions order in this case?

More specifically, I have the following transaction chains within a single shard:

  • 1st_external_msg -> A -> B -> Z
  • 2nd_external_msg -> X -> Y -> Z

I know, that external messages are shuffled, but for example, if 1st_external_msg is placed earlier after shuffling, will the chain 1st_external_msg -> A -> B -> Z be processed earlier, than the 2nd chain? Does dispatch queue have impact in this case?

Thank you!

UPD: I just looked through the blockchain code and see, that dispatch queue processing happens before external messages processing and new messages processing. So the question about dispatch queue impact on transactions order in my case is already addressed. Now just trying to discover the transactions order logic in total.

UPD 2: I clarified the answer on my question:

if 1st_external_msg is placed earlier after shuffling, will the chain 1st_external_msg -> A -> B -> Z be processed earlier, than the 2nd chain (within a single shard and a single block)

So it's yes.

So now I don't have questions.

@zaaki555

This comment was marked as spam.

@EmelyanenkoK EmelyanenkoK merged commit 7489599 into ton-blockchain:master Nov 24, 2024
Copy link

@AfeworkShalom09 AfeworkShalom09 left a comment

Choose a reason for hiding this comment

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

I need view

@@ -0,0 +1,66 @@
- **TEP**: [160](https://github.com/ton-blockchain/TEPs/pull/160) *(don't change)*

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants